Re[2]: Начать ли использовать Code Contracts?
От: ionoy Эстония www.ammyui.com
Дата: 17.08.15 08:38
Оценка:
Здравствуйте, Poopy Joe, Вы писали:


S>>Как сейчас? Использовать старые добрые исключения или же переходить на сабж?

PJ>Нет. Вместо проверки значения типа в рантайме лучше использовать в параметрах тип в котором недопустимые значения просто невозможны.

А можно увидеть реальный проект, где используется подобный подход на полную катушку? Желательно C# конечно, но можно и на Хаскеле, если на шарпе нет.
Я как-то пробовал нечто подобное у себя реализовать, получилось неудобно и я быстро вернулся к обычным проверкам. Может неправильно готовил
www.livexaml.com
www.ammyui.com
www.nemerleweb.com
Re[33]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 17.08.15 09:12
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Ну так твой тоже работает не верно

Ты не просил рабочий, ты просил сигнатуры, чтобы передать идею. Вот как раз код более чем очевидно передает идею, что ошибка будет видна во время компиляции.

Doc>Тебе уже не только я сказал — одинаковые контракты на методах это очень не частое явление. С тем же успехом ты можешь каждый if в коде заворачивать в класс. Но ты придумал себе что-то, сделал из этих фантазий выводы ...

Не очень частое, однако встретилось в первом же случае, причем придуманном тобой, причем чтобы показать обратное.
И так кстати все обсуждение.
Ты заявляешь, что код на типах легко сломать и не можешь это продемонстрировать, предъявляя свой код, который сломать легко.
Ты заявляешь, что пользователю будет непонятно и надо будет смотреть метод, и предъявляешь код который в котором контракт можно узнать только просмотрев сам метод, который может быть обфусцирован или контракты вообще удалены в релизе.
Ты заявляешь, что проверок надо больше и копипастишь код, а вторую часть где проверок еще больше вообще стесняешься привести.
Ты заявляешь, что ошибки труднее увидеть и приводишь код с ошибками, который "по крайней мере компилируется", т.е. скрывает ошибку до времени исполнения.
Итд...
Я уж даже не знаю как еще очевиднее можно показать кривость контрактов.

PJ>>Одно и то же условие проверятся в 3х местах, т.е. нарушаются все приличные практики.

Doc>Придуманные тобой?
Практики не копипастить код придуманы мной?
Re[3]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 17.08.15 09:19
Оценка: :))
Здравствуйте, ionoy, Вы писали:

I>А можно увидеть реальный проект, где используется подобный подход на полную катушку? Желательно C# конечно, но можно и на Хаскеле, если на шарпе нет.

I>Я как-то пробовал нечто подобное у себя реализовать, получилось неудобно и я быстро вернулся к обычным проверкам. Может неправильно готовил

Каким образом ты себе это представляешь? Выкладывать проекты? Я этого, разумеется, делать не буду. Неудобно у тебя, скорее всего, получается, потому что требует некоторого изменения мышления. Я могу посоветовать смотреть как это работает в функциональных языках, хоть на f#, а потом уже самому захочется переносить практики и на c#. Но на c# писать придется больше, хоть он постепенно и перенимает функциональные фичи.
Re[4]: Начать ли использовать Code Contracts?
От: ionoy Эстония www.ammyui.com
Дата: 17.08.15 09:24
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

PJ>Здравствуйте, ionoy, Вы писали:


I>>А можно увидеть реальный проект, где используется подобный подход на полную катушку? Желательно C# конечно, но можно и на Хаскеле, если на шарпе нет.

I>>Я как-то пробовал нечто подобное у себя реализовать, получилось неудобно и я быстро вернулся к обычным проверкам. Может неправильно готовил

PJ>Каким образом ты себе это представляешь? Выкладывать проекты? Я этого, разумеется, делать не буду.

То есть подобных проектов в открытом доступе нет? Есть ли на это причины?
www.livexaml.com
www.ammyui.com
www.nemerleweb.com
Re[5]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 17.08.15 09:43
Оценка:
Здравствуйте, ionoy, Вы писали:

PJ>>Каким образом ты себе это представляешь? Выкладывать проекты? Я этого, разумеется, делать не буду.

I>То есть подобных проектов в открытом доступе нет? Есть ли на это причины?
Эээ... не знаю. Просто лично я в открытых проектах не участвую и не слежу за ними, соответственно помочь тебе с этим не могу.
Re[34]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 17.08.15 09:59
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

PJ>Здравствуйте, Doc, Вы писали:


Doc>>Ну так твой тоже работает не верно

PJ>Ты не просил рабочий, ты просил сигнатуры, чтобы передать идею. Вот как раз код более чем очевидно передает идею, что ошибка будет видна во время компиляции.

Ну это уже совсем отмазка. Я так могу сказать что по BL email надо проверять только на null и "", а возраст может быть отрицательным или очень большим. Ведь ты обратного тоже не просил. А показать как пишутся контракты — тот код как раз.

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


Где? Я так подозреваю что на "Contract.Requires(user != null);" будешь тыкать. Только это такая же копипаста, как и любой if.
И кстати, если несколько методов одного класса требует вдруг одинакового, то ничего не мешает завернуть требования в private метод и использовать его во всех указаниях.

Кстати, вот это все контракт (а не куча мелких контрактов)
Contract.Requires(user != null);
Contract.Requires(user.Sex == Sex.Female);
Contract.Requires(_minAdultAge <= user.Age);
Contract.Requires(user.HairColor == HairColor.Blond);


PJ>Ты заявляешь, что код на типах легко сломать и не можешь это продемонстрировать, предъявляя свой код, который сломать легко.


Ты как его и не сломал. Равно как и не показал откуда в классах у тебя магическим образом появится проверка "возраст меньше 0".

PJ>Ты заявляешь, что пользователю будет непонятно и надо будет смотреть метод, и предъявляешь код который в котором контракт можно узнать только просмотрев сам метод, который может быть обфусцирован или контракты вообще удалены в релизе.


Сам понял что сказал то? Сборка то может быть и без контрактов, и обфусцирована... Контракты то в исходниках останутся. А для библиотек с закрытым кодом пишется документация.

PJ>Ты заявляешь, что проверок надо больше и копипастишь код, а вторую часть где проверок еще больше вообще стесняешься привести.


Какую вторую часть? Опять твои фантазии?

PJ>Ты заявляешь, что ошибки труднее увидеть и приводишь код с ошибками, который "по крайней мере компилируется", т.е. скрывает ошибку до времени исполнения.


Ошибки опять же придумал ты. У тебя в коде нет проверок, о чем еще говорить.

PJ>>>Одно и то же условие проверятся в 3х местах, т.е. нарушаются все приличные практики.

Doc>>Придуманные тобой?
PJ>Практики не копипастить код придуманы мной?

Там нет копипасты. Чуть-чуть подучи мат. часть (редко, но бывает даже что 1 в 1 совпадающий по коду метод не является копипастой, вот ужас).

В итоге мы имеем твой вариант, при котором код
— раздут из расчета по классу на каждую проверку, что породит огромное число классов
— все это необходимо сопровождать, помнить какие проверки есть, а каких еще нет (чтобы не продублировать)
— на все эти классы необходимы unit test, что потребует еще код (кроме тестов на сами методы конечно).
— эти классы проверок жестко связанны с различными классами логики, поэтому менять из код надо с большой осторожностью и полной проверкой всего затронутого кода.

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

И это ты еще не показал как будешь проверять постусловия и инварианты Как классы будут работать в случае интерфейсов (особенно если в условии контракта участвует его же свойства).
Re[35]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 17.08.15 10:45
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Ну это уже совсем отмазка. Я так могу сказать что по BL email надо проверять только на null и "", а возраст может быть отрицательным или очень большим. Ведь ты обратного тоже не просил. А показать как пишутся контракты — тот код как раз.

Ну вот это и будет отмазка. Так как все знают, что такое email. Если у тебя в требования только проверка на null, то ошибка в требованиях и не более того.
Я тебе указываю на очевидные проблемы. Если у тебя трудности в принятием критики, то так и скажи, чего тут кругами-то ходить?

Doc>Где? Я так подозреваю что на "Contract.Requires(user != null);" будешь тыкать. Только это такая же копипаста, как и любой if.

Doc>И кстати, если несколько методов одного класса требует вдруг одинакового, то ничего не мешает завернуть требования в private метод и использовать его во всех указаниях.
Тыкал бы, не сделай МС решение этой проблемы столь неудобным, что проще смирится. За этом им лучи поноса.
Заворачивание в метод мешает во-первых нарушением принципа единой ответственности, а, во-вторых, опять требует дублирования в другом классе.

Doc>Ты как его и не сломал. Равно как и не показал откуда в классах у тебя магическим образом появится проверка "возраст меньше 0".

Ты его, для начала, и не привел. То, что ты привел ломается просто отсылкой случайных параметров. Компилятор даже не пикнет.

Doc>Сам понял что сказал то? Сборка то может быть и без контрактов, и обфусцирована... Контракты то в исходниках останутся. А для библиотек с закрытым кодом пишется документация.

Т.е. мне либу еще и с иходниками надо отдавать? "Сам понял что сказал то?" (с)
Ты тужился доказать, что пользователю надо смотреть в мой код, но доказал ровно обратное — с контрактами легко ошибиться, если не читать документацию и не ковыряться в исходниках. Спасибо!

Doc>Какую вторую часть? Опять твои фантазии?

Использование контрактов. Сигнатуры методов сами по себе не интересны.

Doc>Ошибки опять же придумал ты. У тебя в коде нет проверок, о чем еще говорить.

У меня очевидно, что если тип создался, то он валиден. Ты, кстати, сам это признал предложив в IsAdult использовать byte вместо контракта. Это совершенно естественно и разумно. Все что тебе осталось сделать это следующий шаг и понять, что Age лучше байта.

Doc>Там нет копипасты. Чуть-чуть подучи мат. часть (редко, но бывает даже что 1 в 1 совпадающий по коду метод не является копипастой, вот ужас).

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

Doc>- раздут из расчета по классу на каждую проверку, что породит огромное число классов

У тебя тот же самый код, только не в классах. Затрудняя его понимание и поддержку. Проблемы "много классов" в индустрии нет. А вот пропущенные проверки есть.

Doc>- все это необходимо сопровождать, помнить какие проверки есть, а каких еще нет (чтобы не продублировать)

А ты будешь проверять байт на отрицательные значения?

Doc>- на все эти классы необходимы unit test, что потребует еще код (кроме тестов на сами методы конечно).

Даже юнит-тесты писать проще. Так как код изолирован и отвечает только за одно дело.

Doc>- эти классы проверок жестко связанны с различными классами логики, поэтому менять из код надо с большой осторожностью и полной проверкой всего затронутого кода.

Они связаны с логическими сущностями. Возраст есть возраст, он не обязательно ограничен одним контрактом, так же как байт не обязательно ограничен IsAdult.

Doc>И это ты еще не показал как будешь проверять постусловия и инварианты Как классы будут работать в случае интерфейсов (особенно если в условии контракта участвует его же свойства).

Да точно также. Метод возвращает тип. Даже странно, что это надо пояснять отдельно.
Re[36]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 17.08.15 11:18
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

PJ>Я тебе указываю на очевидные проблемы. Если у тебя трудности в принятием критики, то так и скажи, чего тут кругами-то ходить?


Так ты не туда указываешь. Я бы согласился, если бы ты сказал что это я забыл, что это моя ошибка. Но нет, ты сказал что это проблема контрактов. Хотя сделать не ту проверку можно хоть в контракте, хоть в классе. И вылезет она в обоих случаях только на этапе юнит-тестов, а не компиляции. Согласен?

PJ>Заворачивание в метод мешает во-первых нарушением принципа единой ответственности,


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

PJ>а, во-вторых, опять требует дублирования в другом классе.


Зачем, метод спокойно размещается в том же классе, что и сами контракты.

PJ>Ты его, для начала, и не привел. То, что ты привел ломается просто отсылкой случайных параметров. Компилятор даже не пикнет.


Ты тестируй тогда оба кода одинаково, а то у меня до проверок доколупался, т.к. до самих контрактов не смог.
По этой твоей логике, твой код уже сломан, т.к. не содержит проверок

Doc>>Сам понял что сказал то? Сборка то может быть и без контрактов, и обфусцирована... Контракты то в исходниках останутся. А для библиотек с закрытым кодом пишется документация.

PJ>Т.е. мне либу еще и с иходниками надо отдавать? "Сам понял что сказал то?" (с)

Ты сам процитировал "А для библиотек с закрытым кодом пишется документация."
А если библиотека используется внутри команды или open source — то исходники и так у всех есть.

PJ>Ты тужился доказать, что пользователю надо смотреть в мой код, но доказал ровно обратное — с контрактами легко ошибиться, если не читать документацию и не ковыряться в исходниках. Спасибо!


Да, да, лучше написать неработающий код с кучей классов.

Doc>>Какую вторую часть? Опять твои фантазии?

PJ>Использование контрактов. Сигнатуры методов сами по себе не интересны.

Обычные вызовы. Не вижу там ничего особого. Но если тебе хочется то вот:
Я понимаю что ты сейчас заорешь про try/catch, но их тут нет, т.к. обработка исключений идет на уровне всего приложения.
Я показываю просто вызовы. При правильной BL все userN получат валидные данные и исключений не будет.

var someClass = new SomeClass();

var user = this._someRepo.LoadCurrentUser();
bool isAdult = someClass.IsAdult(user.Age);
...
var user1 = this._someRepo.LoadAdultUser();
someClass.DoSomething1(user1.Email, user1.Age);
...
someClass.DoSomething2(user2);
someClass.DoSomething3(user3);
someClass.DoSomething4(user4);
someClass.DoSomething5(user5);
...


PJ>У меня очевидно, что если тип создался, то он валиден.

Абстрактное утверждение. Валидным он может быть по отношению к какому-то условию.

PJ>Ты, кстати, сам это признал предложив в IsAdult использовать byte вместо контракта. Это совершенно естественно и разумно. Все что тебе осталось сделать это следующий шаг и понять, что Age лучше байта.


Если мы можем взять готовый тип, то почему бы и нет. Byte в отличии от Age не содержит проверок и универсален.
Age тянет за собой лишний связи и лишний код.

PJ>Не знаю какая там у тебя матчасть и где ты ее брал, но если на изменение одной константы, возраста, тебе надо поменять три строки, то это копипаста.


И где ты три насчитал? (1) Есть переменная для класса. (2) можно сделать метод.
Но у тебя опять фантазии.

PJ>Проблемы "много классов" в индустрии нет. А вот пропущенные проверки есть.


Да ладно? Нет? Все так и рады когда объем кода все растет, а значит затраты на его поддержку растут ... и все этому рады? Правда?
Плюс ты все еще не показал как волшебным образом пропущенные проверки сами появятся в твоих классах.

PJ>А ты будешь проверять байт на отрицательные значения?


А ты про байт? Вроде же у тебя классы?

PJ>Даже юнит-тесты писать проще. Так как код изолирован и отвечает только за одно дело.


Чем проще? Т.е. тесты для метода + еще бонусом тесты для классов с типами.


Doc>>И это ты еще не показал как будешь проверять постусловия и инварианты Как классы будут работать в случае интерфейсов (особенно если в условии контракта участвует его же свойства).

PJ>Да точно также. Метод возвращает тип. Даже странно, что это надо пояснять отдельно.

Это ты так типа не заметил про инварианты класса и интерфейсы?
Re[37]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 17.08.15 12:22
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Так ты не туда указываешь. Я бы согласился, если бы ты сказал что это я забыл, что это моя ошибка. Но нет, ты сказал что это проблема контрактов. Хотя сделать не ту проверку можно хоть в контракте, хоть в классе. И вылезет она в обоих случаях только на этапе юнит-тестов, а не компиляции. Согласен?

Конечно контрактов, потому что не помогли выявить. Нафиг тогда они нужны? Ошибку можно сделать где угодно, но опять же:
В типе есть сделать сложнее, так как его назначение очевидно. Во-вторых, проще заметить. Первый же тест с невалидным емайлом это укажет, потому как тестируется именно он. Если ошибка нашлась, то исправить ее надо ровно в одном месте.

Doc>Ага, а заворачивание в отдельный класс — нет? Логика проверки остается в том же классе, которому она и принадлежит.

С чего вдруг рассылатель емейла малолеткам должен еще и решать кого считать малолетками?

PJ>>а, во-вторых, опять требует дублирования в другом классе.


Doc>Зачем, метод спокойно размещается в том же классе, что и сами контракты.


PJ>>Ты его, для начала, и не привел. То, что ты привел ломается просто отсылкой случайных параметров. Компилятор даже не пикнет.


Doc>Ты тестируй тогда оба кода одинаково, а то у меня до проверок доколупался, т.к. до самих контрактов не смог.

Doc>По этой твоей логике, твой код уже сломан, т.к. не содержит проверок
Да, именно так. В продакшн такой код допускать нельзя. Еще смешнее приводить его пример с какой-нибудь вендинговой машиной "где большие штрафы".

Doc>Ты сам процитировал "А для библиотек с закрытым кодом пишется документация."

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

Doc>А если библиотека используется внутри команды или open source — то исходники и так у всех есть.

Т.е. контракты уже имеют кучу ограничений?! А если нет? А если сначала внутри команды, а потом решили отдать наружу?

Doc>Да, да, лучше написать неработающий код с кучей классов.

Не копилирующийся. Да лучше.
Он вполне работающий, ошибка там в одном месте, где надо либо каст добавить, либо селект. Ну так компилятор на это и укажет, и я просто не смогу собрать невалидный код, в отличии от "хотя бы компилируется".

Doc>Обычные вызовы. Не вижу там ничего особого. Но если тебе хочется то вот:

Ну так пример кода, который может свалится в любой, потому что никаких проверок чего там в LoadCurrentUser нет. Это криво даже с контрактами. Особенно с контрактами, потому что с одной стороны ты требуешь соответствие контракту, а с другой не делаешь никаких усилий для выполнения.

PJ>>У меня очевидно, что если тип создался, то он валиден.

Doc>Абстрактное утверждение. Валидным он может быть по отношению к какому-то условию.
Нет, это аксиома. Тип должен быть внутренне непротиворечив и все. Если у тебя другие условия, то и тип должен быть другим.

Doc>Если мы можем взять готовый тип, то почему бы и нет. Byte в отличии от Age не содержит проверок и универсален.

Doc>Age тянет за собой лишний связи и лишний код.
Ну тогда надо вообще отказаться от типов, раз это лишний код.

Doc>И где ты три насчитал? (1) Есть переменная для класса. (2) можно сделать метод.

Doc>Но у тебя опять фантазии.
Ну будут дублироваться методы, какая разница? Предложишь вообще все держать в одном классе?

Doc>Да ладно? Нет? Все так и рады когда объем кода все растет, а значит затраты на его поддержку растут ... и все этому рады? Правда?

Doc>Плюс ты все еще не показал как волшебным образом пропущенные проверки сами появятся в твоих классах.
Объем кода никак не связан с количеством классов. Может хоть на ассемблере его увеличивать. Твои контракты увеличивают код — откажись от контрактов.

Doc>А ты про байт? Вроде же у тебя классы?

У меня типы. Байт ты не проверяешь, потому что знаешь его свойства. С Age все точно так же.

Doc>Чем проще? Т.е. тесты для метода + еще бонусом тесты для классов с типами.

Тем, что проверяя Age или Email ты концентрируешься на их проблемах и их граничных условиях. Когда ты пишешь тип Email ты наверняка проверишь его валидность, а с контрактом тебе это и в голову не пришло.

Doc>Это ты так типа не заметил про инварианты класса и интерфейсы?

Они ничего не меняют.
Re[38]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 17.08.15 16:17
Оценка: +1
Здравствуйте, Poopy Joe, Вы писали:

PJ>Конечно контрактов, потому что не помогли выявить. Нафиг тогда они нужны?

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

PJ>Ошибку можно сделать где угодно, но опять же:

PJ>В типе есть сделать сложнее, так как его назначение очевидно.

Т.е. опять все дело в программисте. Сделал — не сделал, увидел — не увидел.
Кстати, назначение метода еще очевиднее.

PJ> Первый же тест с невалидным емайлом это укажет, потому как тестируется именно он.


Аналогично тест выявит и ошибку в контракте.

PJ> Если ошибка нашлась, то исправить ее надо ровно в одном месте.


То же самое (а в том редком случае, на который ты давишь, можно сделать метод)

Doc>>Ага, а заворачивание в отдельный класс — нет? Логика проверки остается в том же классе, которому она и принадлежит.

PJ>С чего вдруг рассылатель емейла малолеткам должен еще и решать кого считать малолетками?

Согласен. По хорошему это вообще 2 разных класса. BL формирует список кому слать, а сервис рассылает по списку. BL в соответствующем методе имеет постусловие в контракте, а сервис валидирует email.

PJ>>>Ты его, для начала, и не привел. То, что ты привел ломается просто отсылкой случайных параметров. Компилятор даже не пикнет.


Твой так же делает фигню и не компилируется. Мне уже надоело тебе это повторять, поэтому претензии к коду, а не контрактам я буду игнорить.

Doc>>Ты сам процитировал "А для библиотек с закрытым кодом пишется документация."

PJ>Ну я просто не стал тыкать тебя носом в хорошую практику не ставить свой код в зависимость от чтения документации другими. Но если ты настаиваешь...

Ну я понимаю что тебе надо все разжевывать, поэтому расскажу тебе что еще можно называть методы и параметры осмыслено, что уже документирует.
Кроме того, документация пишется не сколько в хелп файле, а в XML комментах, которые хорошо показывает IntelliSense.

Doc>>А если библиотека используется внутри команды или open source — то исходники и так у всех есть.

PJ>Т.е. контракты уже имеют кучу ограничений?! А если нет? А если сначала внутри команды, а потом решили отдать наружу?

См. выше. Для выдачи наружу ты все равно будешь (сам или волонтеры) писать документацию и примеры. Иначе твоя либа сгинет никому не нужной.
И потом — нет смысла писать "тут есть контракт который валидирует". И для твоей схемы с типами и для контрактов пишется "параметр email — принимает корректный email адрес для отправки. Не может быть null"

PJ>Он вполне работающий, ошибка там в одном месте, где надо либо каст добавить, либо селект.


Не, не, не... раз это твои классы "не помогли выявить. Нафиг тогда они нужны?"

PJ>Ну так пример кода, который может свалится в любой, потому что никаких проверок чего там в LoadCurrentUser нет. Это криво даже с контрактами. Особенно с контрактами, потому что с одной стороны ты требуешь соответствие контракту, а с другой не делаешь никаких усилий для выполнения.


Я тебе написал что выдать правильные данные — забота этого метода. Придирайся дальше.

PJ>Ну будут дублироваться методы, какая разница? Предложишь вообще все держать в одном классе?


Все зависит от того, что это за проверка, раз она нужна много где. Что-то останется в 1 классе, а что-то может уйти в extension метод.

Doc>>А ты про байт? Вроде же у тебя классы?

PJ>У меня типы. Байт ты не проверяешь, потому что знаешь его свойства. С Age все точно так же.

Байт проверен разработчиками C#. Я доверяю С# и используемым библиотекам. Свое — тестируется.
А ты выходит просто доверяешь своим классам и не тестируешь их? Ну да, ну да...

Doc>>Чем проще? Т.е. тесты для метода + еще бонусом тесты для классов с типами.

PJ>Тем, что проверяя Age или Email ты концентрируешься на их проблемах и их граничных условиях. Когда ты пишешь тип Email ты наверняка проверишь его валидность, а с контрактом тебе это и в голову не пришло.

Ну по твоей такой логике в твоем примере ты вообще ничего не проверил. Значит у тебя вообще пусто?

Doc>>Это ты так типа не заметил про инварианты класса и интерфейсы?

PJ>Они ничего не меняют.

Да ну... Ну покажи инвариант для интерфейса.
public interface IDemo {
    byte A { get; set; }
    byte B { get; set; }
    byte C { get; set; }
}

Инвариант — сумма A+B+C < 200

1) 1 имплементацию пишешь ты
2) Там как видишь public и юзер легко может написать свою, как его заставишь соблюдать?
Re[39]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 17.08.15 17:24
Оценка:
Здравствуйте, Doc, Вы писали:

PJ>>Конечно контрактов, потому что не помогли выявить. Нафиг тогда они нужны?

Doc>Тогда и классы-типа нафиг, т.к. они ровным счетом так же себя поведут.
Нет, не так же.

Doc>Т.е. опять все дело в программисте. Сделал — не сделал, увидел — не увидел.

Doc>Кстати, назначение метода еще очевиднее.
Ну понятно, что всегда дело в программисте. Но, в одном случае компилятор может помочь, а в другом программист будет рассказывать как важно составлять правильную документацию и отдавать сорцы либы.

PJ>> Первый же тест с невалидным емайлом это укажет, потому как тестируется именно он.


Doc>Аналогично тест выявит и ошибку в контракте.

Ага, и так тесты для всех месте где есть емайл в контрактах. Не копипаст, ага.

Doc>Согласен. По хорошему это вообще 2 разных класса. BL формирует список кому слать, а сервис рассылает по списку. BL в соответствующем методе имеет постусловие в контракте, а сервис валидирует email.

Че то ты сам себе противоречишь. Какой отдельный класс, их надо экономить.

Doc>Твой так же делает фигню и не компилируется. Мне уже надоело тебе это повторять, поэтому претензии к коду, а не контрактам я буду игнорить.

Так это и есть претензии. У меня фигня не компилируется,а у тебя фигня копилируется. А чего ты еще от компилятора ждешь? Что за тебя код писать будет?

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

Doc>Кроме того, документация пишется не сколько в хелп файле, а в XML комментах, которые хорошо показывает IntelliSense.
А... Ну понятно, а если использовать венгерскую нотацию, то вообще можно на типы забить...

Doc>См. выше. Для выдачи наружу ты все равно будешь (сам или волонтеры) писать документацию и примеры. Иначе твоя либа сгинет никому не нужной.

Doc>И потом — нет смысла писать "тут есть контракт который валидирует". И для твоей схемы с типами и для контрактов пишется "параметр email — принимает корректный email адрес для отправки. Не может быть null"
А зачем тогда вообще все ооп, паттрерны, компиляторы? Да ограничиться одним фортраном и писать документацию. Навыдумывали ерунды...

Doc>Не, не, не... раз это твои классы "не помогли выявить. Нафиг тогда они нужны?"

Так помогли. В отличии от твоих контрактов.

Doc>Я тебе написал что выдать правильные данные — забота этого метода. Придирайся дальше.

Что такое "правильные данные"? Там три разных контракта. Тут даже придираться не надо, все очевидно. Ты сам отлично закапываешь свои контракты.

Doc>Все зависит от того, что это за проверка, раз она нужна много где. Что-то останется в 1 классе, а что-то может уйти в extension метод.

Как опять отдельный класс? Я не ослышался?

Doc>Байт проверен разработчиками C#. Я доверяю С# и используемым библиотекам. Свое — тестируется.

Doc>А ты выходит просто доверяешь своим классам и не тестируешь их? Ну да, ну да...
Ну так и говори, что ты доверяешь разработчикам c#, а себе нет. Причем как-то странно. С контрактами доверяешь, причем даже с очевидными ошибками.

Doc>Ну по твоей такой логике в твоем примере ты вообще ничего не проверил. Значит у тебя вообще пусто?

В моей логике проверки внутренние. А в твоей логике они непонятно где. Вариант, что один метод вернет верные данные для трех взаимоисключающих контрактов — смешон.

Doc>Да ну... Ну покажи инвариант для интерфейса.

Doc>
public interface IDemo {
Doc>    byte A { get; set; }
Doc>    byte B { get; set; }
Doc>    byte C { get; set; }
Doc>}

Doc>Инвариант — сумма A+B+C < 200

И чем это вариант отличается от твоего предыдущего примера с возрастом и весом?

Doc>1) 1 имплементацию пишешь ты

Doc>2) Там как видишь public и юзер легко может написать свою, как его заставишь соблюдать?
Хм... так предлагаешь писать реализацию IDemo с инвариантом?
Не, ну против дурака с клавиатурой приема конечно нет. Сломать можно все.
Но в прошлом сообщении я тебе сказал, что правильное использование типов основано на аксиоме непротиворечивости типа, что в твоем случае не выполняется. В данном случае проблема находится за пределами и типов, и контрактов.
Re[40]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 18.08.15 01:52
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

Doc>>Тогда и классы-типа нафиг, т.к. они ровным счетом так же себя поведут.

PJ>Нет, не так же.

Ты выше написал что так же. Не отпирайся

PJ>Ну понятно, что всегда дело в программисте. Но, в одном случае компилятор может помочь, а в другом программист будет рассказывать как важно составлять правильную документацию и отдавать сорцы либы.


У тебя код без единого условия и компиялятор не помог. Так что по твоей же логике "нафиг классы".

PJ>Ага, и так тесты для всех месте где есть емайл в контрактах. Не копипаст, ага.


Если вдруг тест будет нужен больше раза — extension метод не запрещали.

PJ>Так это и есть претензии. У меня фигня не компилируется,а у тебя фигня копилируется. А чего ты еще от компилятора ждешь? Что за тебя код писать будет?


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

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

Doc>>Кроме того, документация пишется не сколько в хелп файле, а в XML комментах, которые хорошо показывает IntelliSense.
PJ>А... Ну понятно, а если использовать венгерскую нотацию, то вообще можно на типы забить...

Ну если для тебя осмысленные названия параметров это как венгерская нотация (которая кстати не отменяет типы, а описывает их)...
Твоему коду поди и обфускация не нужна

PJ>А зачем тогда вообще все ооп, паттрерны, компиляторы? Да ограничиться одним фортраном и писать документацию. Навыдумывали ерунды...


Как одно отменяет другое? Уже бред несешь. IntelliSense (документацией) я так понимаю ты вообще не пользуешся? В блокноте пишешь?

Doc>>Не, не, не... раз это твои классы "не помогли выявить. Нафиг тогда они нужны?"

PJ>Так помогли. В отличии от твоих контрактов.

Да? Ну подтверди примером, покажи что за текст ошибки будет. Что там про логику проверки написано

Doc>>Я тебе написал что выдать правильные данные — забота этого метода. Придирайся дальше.

PJ>Что такое "правильные данные"? Там три разных контракта. Тут даже придираться не надо, все очевидно. Ты сам отлично закапываешь свои контракты.

Только в твоей фантазии.

Doc>>Все зависит от того, что это за проверка, раз она нужна много где. Что-то останется в 1 классе, а что-то может уйти в extension метод.

PJ>Как опять отдельный класс? Я не ослышался?

Нет.

PJ>Ну так и говори, что ты доверяешь разработчикам c#, а себе нет.


Это понимать как признание что ты не доверяешь разработчикам C# и базовые типы тестишь?

Doc>>Ну по твоей такой логике в твоем примере ты вообще ничего не проверил. Значит у тебя вообще пусто?

PJ>В моей логике проверки внутренние. А в твоей логике они непонятно где. Вариант, что один метод вернет верные данные для трех взаимоисключающих контрактов — смешон.

Один метод? Ты код точно читать умеeшь или с фантазиями?

PJ>Хм... так предлагаешь писать реализацию IDemo с инвариантом?


У тебя с этим сложность?

PJ>Не, ну против дурака с клавиатурой приема конечно нет. Сломать можно все.


Ну вот тебе код. И жду от тебя аналог на классах-типах.
Первый пример на интерфейсах. Тут чуть сложнее, т.к. прямой поддержки инвариантов для интерфейсов нет. Но тем не менее все реализации интерфейса будут соблюдать указанное правило:
        [ContractClass(typeof(DemoContract))]
        public interface IDemo
        {
            byte A { get; set; }
            byte B { get; set; }
            byte C { get; set; }
        }
        
        [ContractClassFor(typeof(IDemo))]
        internal abstract class DemoContract : IDemo
        {
            public byte A
            {
                get { return default(byte); }
                set { Contract.Requires(DemoContractInvariant.ClassInvariant(value, this.B, this.C)); }
            }

            public byte B
            {
                get { return default(byte); }
                set { Contract.Requires(DemoContractInvariant.ClassInvariant(this.A, value, this.C)); }
            }
            public byte C
            {
                get { return default(byte); }
                set { Contract.Requires(DemoContractInvariant.ClassInvariant(this.A, this.B, value)); }
            }
        }

        public static class DemoContractInvariant
        {
            [Pure]
            public static bool ClassInvariant(byte a, byte b, byte c)
            {
                return a + b + c < 200;
            }
        }

Ну и использование:
        public class Demo1 : IDemo
        {
            public byte A { get; set; }
            public byte B { get; set; }
            public byte C { get; set; }
        }

        ...

        IDemo d1 = new Demo1();
        d1.A = 100;
        d1.B = 99;
        d1.C = 100;


В случае с абстрактными классами все проще:
        public abstract class Demo 
        {
            public byte A { get; set; }
            public byte B { get; set; }
            public byte C { get; set; }

            [ContractInvariantMethod]
            private void ObjectInvariant()
            {
                Contract.Invariant(this.A + this.B + this.C < 200);
            }
        }

        public class Demo2 : Demo
        {
        }

        ...

        Demo d2 = new Demo2();
        d2.A = 100;
        d2.B = 99;
        d2.C = 100;


Жду ответный вариант
Re[41]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 18.08.15 10:49
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>У тебя код без единого условия и компиялятор не помог. Так что по твоей же логике "нафиг классы".

Помог.

Doc>Если вдруг тест будет нужен больше раза — extension метод не запрещали.

Если он вдруг понадобится второй раз, то другой сотрудник о твоем контракте и знать-то не будет. Он тупо добавить еще одну проверку в свой метод.

Doc>Да, и прям в ошибках компилятора будет указано что ты логику не написал? или что-то иное?

Да вот прям так и напишет. Что типы не приводятся. Вся логика по сути это и есть трансформация типов. Здорово, правда?!

Doc>Ну если для тебя осмысленные названия параметров это как венгерская нотация (которая кстати не отменяет типы, а описывает их)...

Doc>Твоему коду поди и обфускация не нужна
Осмысленные названия никак не заменяют проверку типов компилятором. Удивительно, что ты тут вообще взялся спорить.

Doc>Как одно отменяет другое? Уже бред несешь. IntelliSense (документацией) я так понимаю ты вообще не пользуешся? В блокноте пишешь?

Я не говорил, что оно отменяет, это из твоих слов следует. Количество классов считаешь, типизацию заменяешь на "правильное название параметров" итд.

Doc>>>Я тебе написал что выдать правильные данные — забота этого метода. Придирайся дальше.

PJ>>Что такое "правильные данные"? Там три разных контракта. Тут даже придираться не надо, все очевидно. Ты сам отлично закапываешь свои контракты.

Doc>Только в твоей фантазии.

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

Doc>Это понимать как признание что ты не доверяешь разработчикам C# и базовые типы тестишь?

Хмм... даже не представляю как можно было сделать такой вывод.

Doc>Один метод? Ты код точно читать умеeшь или с фантазиями?

У тебя один LoadUser. Насчитай там больше.

Doc>Ну вот тебе код. И жду от тебя аналог на классах-типах.

Ну тут детали зависят от некоторых условий. Если это внутренний тип, то он просто выкидывается, как глупый. Ну и, понятно, только идиот может написать интерфейс с публичным сеттером и инвариантом на три из них. Если интерфейс внешний и требует инвариант, то тут конечно и надо что-то писать.
public class DemoContainer<T> where T : IDemo
{
    readonly IDemo _demo
    DemoContainer() {};

    public static Optional<DemoContainer> Create(IDemo demo) 
        => demo.a + demo.b + demo.c < 200 ? Optional.Create(new DemoContainer(demo)) : Optional.Nothing();
}

иcпользование просто 
void DemoConsumer(DemoContainer<IDemo> demo) {}

К сожалению readonly не гарантирует, что изменять _demo нельзя, поэтому DemoContainer не дает доступа к _demo, в лишь к его геттерам. Писать все лениво, но идея и так понятна.
Re[42]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 18.08.15 13:05
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

PJ>Помог.


Не помог. (если помог, показывай где сообщение об ошибке в логике)

PJ>Если он вдруг понадобится второй раз, то другой сотрудник о твоем контракте и знать-то не будет. Он тупо добавить еще одну проверку в свой метод.


C тем же успехом можно и копию класса сделать. (а дубли кода, кстати, VS искать умеет).

Doc>>Да, и прям в ошибках компилятора будет указано что ты логику не написал? или что-то иное?

PJ>Да вот прям так и напишет. Что типы не приводятся. Вся логика по сути это и есть трансформация типов. Здорово, правда?!

Не выкручивайся (да еще так не умело). Что не приводятся типы не говорит о том, что есть ошибка в проверке.
Твой код соберется или не соберется с ошибкой приведения, не зависит от того проверяется email только на null или на валидность.

PJ>Осмысленные названия никак не заменяют проверку типов компилятором. Удивительно, что ты тут вообще взялся спорить.


Опять споришь сам с собой и лупишь себя по лицу.

Doc>>>>Я тебе написал что выдать правильные данные — забота этого метода. Придирайся дальше.

PJ>>>Что такое "правильные данные"? Там три разных контракта. Тут даже придираться не надо, все очевидно. Ты сам отлично закапываешь свои контракты.

Опять словоблудие, непонятная радость и ноль фактов. Подскажу, там если поглядишь специально показано что передаются разные переменные. Дальше разжёвывать не буду.

Doc>>Один метод? Ты код точно читать умеeшь или с фантазиями?

PJ>У тебя один LoadUser. Насчитай там больше.

Погляди на текст и имена переменных.

PJ>Ну тут детали зависят от некоторых условий. Если это внутренний тип, то он просто выкидывается, как глупый.


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

PJ> public static Optional<DemoContainer> Create(IDemo demo)

PJ> => demo.a + demo.b + demo.c < 200 ? Optional.Create(new DemoContainer(demo)) : Optional.Nothing();
PJ>}

И что помешает другому программисту инициализировать и передать свою реализацию в метод который принимает IDemo? В случае с контрактом, можешь написать свою реализацию, можешь уточнить контракт (сделав его строже), то соблюдать оригинальный контракт будут все реализации.
Re[43]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 18.08.15 13:38
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Не помог. (если помог, показывай где сообщение об ошибке в логике)

Неверный тип и есть ошибка в логике. Сколько раз еще надо это повторить?

Doc>C тем же успехом можно и копию класса сделать. (а дубли кода, кстати, VS искать умеет).

Копии классов видны в иерархии, а какие-то строки внутри методов — нет. Ничего не помешает конечно, но вероятность, с контрактами, выше.

Doc>Твой код соберется или не соберется с ошибкой приведения, не зависит от того проверяется email только на null или на валидность.

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

Doc>Опять споришь сам с собой и лупишь себя по лицу.

Это не я доказываю как здорово можно заменить проверку типов правильными названиями.

Doc>Опять словоблудие, непонятная радость и ноль фактов. Подскажу, там если поглядишь специально показано что передаются разные переменные. Дальше разжёвывать не буду.

Это у тебя словоблудие. Используется один LoadUser и три вызова подряд с взаимоисключающими контрактами. На каких-то из них он будет постоянно валится.
Ты привел пример программы которая только и делает, что валится. Че тут разжевывать? И так все понятно.

Doc>Погляди на текст и имена переменных.

Названия переменных не помешают им свалится.

Doc>Ничего выкидывать не надо. Пример интерфейса для простоты. Если не нравится — нарисуй свой интерфейс, где в инварианте есть связь между некоторыми параметрами, которые могут быть изменены из вне.

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

PJ>> public static Optional<DemoContainer> Create(IDemo demo)

PJ>> => demo.a + demo.b + demo.c < 200 ? Optional.Create(new DemoContainer(demo)) : Optional.Nothing();
PJ>>}

Doc>И что помешает другому программисту инициализировать и передать свою реализацию в метод который принимает IDemo? В случае с контрактом, можешь написать свою реализацию, можешь уточнить контракт (сделав его строже), то соблюдать оригинальный контракт будут все реализации.

Ошибка компилятора, я полагаю, так как метод не принимает IDemо. Всегда ваш, КО.
Re[44]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 18.08.15 15:47
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

Doc>>Не помог. (если помог, показывай где сообщение об ошибке в логике)

PJ>Неверный тип и есть ошибка в логике. Сколько раз еще надо это повторить?

До тех пока пока ты не покажешь логическую цепочку от "не приводится тип" до "нет та проверка email".

Doc>>Твой код соберется или не соберется с ошибкой приведения, не зависит от того проверяется email только на null или на валидность.

PJ>Не зависит. Но если email написан правильно, то он будет работать везде одинаково, вне зависимости от того, забыл пользователь в контракте проверить или нет.

Еще раз как "не приводится тип" обозначает "нет та проверка email"?

Doc>>Погляди на текст и имена переменных.

PJ>Названия переменных не помешают им свалится.

Ну хорошо — найди в коде что все они загружаются одним методом? Не нашел? И не фантазируй.

PJ>Ну да пример глупого интерфейса, с глупыми требованиями.


Это просто пример для разбора. Написать у тебя не вышло, пошла в ход демагогия.

PJ>Я уже говорил, что от дураков защиты нет. В таком случае код надо оборачивать и изолировать, а не контракты лепить к нему.


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

PJ>Ошибка компилятора, я полагаю, так как метод не принимает IDemо. Всегда ваш, КО.


Не тупи Речь о методах, которые потребляют интерфейс. Не обертки, не конкретные реализации, а интерфейсы.
Re[45]: Начать ли использовать Code Contracts?
От: Poopy Joe Бельгия  
Дата: 18.08.15 19:29
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>До тех пока пока ты не покажешь логическую цепочку от "не приводится тип" до "нет та проверка email".

Чего в предложении "тип должен заботится о своем инварианте" ты не понял? Вроде не такая уж и сложная мысль. Тут не надо никаких логических цепочек — это аксиома.

Doc>Ну хорошо — найди в коде что все они загружаются одним методом? Не нашел? И не фантазируй.

Я нашел два метода на пять вызовов.
var user = this._someRepo.LoadCurrentUser();
var user1 = this._someRepo.LoadAdultUser()
Ни один из них не отвечает твоим же требованиям даже по названию. Мне не надо фантазировать. Фантазировать сейчас надо тебе, рассказывая как LoadAdultUser в одном случае загрузит блондинок, в во втором толстушек. Начинай...

Doc>Это просто пример для разбора. Написать у тебя не вышло, пошла в ход демагогия.

Ну так глупый пример. Код я тебе написал, но пример все равно глупый. Но код ты не заметил, зато ударился в демагонию, это верно.

Doc>Ну сознайся что инвариант для интерфейса на типах ты не напишешь. Ты можешь контролировать входные параметры методов через пачку типов.

Doc>Но как только появляется между ними связь, то все — твоя схема не работает.
Зачем мне сознаваться, если я тебе написал? Ты, как ребенок, уже начала клянчить чего-то что ли?

Doc>Не тупи Речь о методах, которые потребляют интерфейс. Не обертки, не конкретные реализации, а интерфейсы.

Это как рассуждать о пользе таблеток от головной боли, если биться головой об стену.
Так не делай методы которые потребляют такие интерфейсы.
Если это внутренний интерфейс, то его надо поменять, если внешний, то обернуть. Вот чего не надо делать, так это реализовывать его с костылями.
Re[45]: Начать ли использовать Code Contracts?
От: Sinix  
Дата: 18.08.15 20:22
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>...


При всём уважении — забейте. Оппонент то ли троллит, то ли не считает нужным читать ответы. В любом их вариантов лучше не кормить.
Re[46]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 19.08.15 01:37
Оценка:
Здравствуйте, Sinix, Вы писали:

S>При всём уважении — забейте. Оппонент то ли троллит, то ли не считает нужным читать ответы. В любом их вариантов лучше не кормить.


Соглашусь с вами. Хотя на троллинг это уже не похоже, уж сильно толсто (только на эмоциях).
Re[46]: Начать ли использовать Code Contracts?
От: Doc Россия http://andrey.moveax.ru
Дата: 19.08.15 01:39
Оценка:
Здравствуйте, Poopy Joe, Вы писали:

Doc>>До тех пока пока ты не покажешь логическую цепочку от "не приводится тип" до "нет та проверка email".

PJ>Чего в предложении "тип должен заботится о своем инварианте" ты не понял? Вроде не такая уж и сложная мысль. Тут не надо никаких логических цепочек — это аксиома.

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

Doc>>Ну сознайся что инвариант для интерфейса на типах ты не напишешь. Ты можешь контролировать входные параметры методов через пачку типов.

Doc>>Но как только появляется между ними связь, то все — твоя схема не работает.
PJ>Зачем мне сознаваться, если я тебе написал? Ты, как ребенок, уже начала клянчить чего-то что ли?

Твой пример работает только для методов, которые принимают обертку. Заставить пользователя, написавшего свою реализацию, соблюдать условия у тебя не вышло. Так что приведенный код только и доказывает что инвариант для интерфейса ты не напишешь.

В общем, учитывая что отвечать на вопросы ты не хочешь, некорректный код (который не решает задачу) ты выдаешь как корректный, и вместо того, чтобы показать свой метод в действии начинаешь демагогию о глубинных смыслах демокода, то смысла общаться дальше я не вижу.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.