Pull to refresh

Comments 16

Учитывая, что контракты теперь пилят не так активно (можно сказать отказались от них, от конкретной реализации), как раньше, то это вызывает боль. Более того, было заявлено, что они сильно замедляют процесс сборки, но не скрою, сам на это я не наткнулся — у меня их не так много используется.
Прошу пояснить вот это:
>>нарушение предусловия всегда говорит о наличие бага в коде клиента

В статье идет речь о том, что предусловие это внутренняя проверка. Т.е. за 'firewall'-ом, в роли которого выступает «проверка входных данных». Как это может быть багой в коде клиента в случае, если клиент передал данные удовлетворяющие входному условию?
В коде клиента — имеется ввиду в коде класса-клиента внутри системы, а не в коде системы, которая вызывает API извне.
Т.е. на первой картинке баг будет в классе Class1.
Чем технически различаются контракты и валидация? Верно ли, что «правильные» контракты должны производить статическую проверку на этапе компиляции, т.е. на if-ах и assert-ах контракт нереализуем? Есть ли альтернативы у проекта CodeContracts?
Контракты в коде — это набор техник, направленных на
1) Документирование поведения кода
2) Обеспечение быстрого фидбека в случае некорректного поведения кода

Проект CodeContracts и статические проверки — инструментарий поверх этих техник. Они полезны, но не являются обязательными.
Мы точно также можем обозначить контракты в коде (как минимум предусловия) с помощью самописных конструкций (сводящихся к обычным if-ам), главное чтобы было очевидно, что это именно контакты, а не что-то другое.
Допустим в моей библиотеке есть класс, который использует программист-пользователь в своем коде. Этот класс CodeReview и допустим в нем есть метод public(filename). Метод берет файл, шлет на веб-ресурс этот файл и публикует файл для коде-ревью. Задачка из головы, метод тоже. Это чтобы предметнее рассуждать.

Есть ситуации:
1. Файла не существует
2. К файлу нет прав по чтению
3. Файл не текстовой, а бинарный к примеру exe-файл с переименованным расширением. Т.е. это не код с точки зрения проводящих коде-ревью
4. Файл слишком огромный. Программист очень постарался(написал скрипт, чтобы сломать систему) и создал файл на 25ГБ
и др. но остановимся

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

З.Ы.: Возможно последнее предложение не совсем ясное. Прошу прощения
Если я правильно понял, вопрос в том, как правильно обозначать проверки в коде и как контракты?
У меня в коде это обычно выглядит так. Предусловия контактов обозначаю через самописный класс Contracts (внутри которого if с выбрасыванием специального исключения в случае невыполнения условия):

public void DeleteUser(User user)
{
    Contracts.Require(user.Status != UserStatus.Deleted);

    user.MarkAsDeleted();
}

Проверки выполняются обычными if-ами:

Organization org = _organizationRepository.GetById(model.OrganizationId);
if (orgOrNothing == null)
    return Error("No organization found for Id = " + model.OrganizationId);

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

Если внутри GetById проверить OrganizationId > 0, это будет контракт или валидация?
Верно ли, что результат невыполнения контракта — всегда исключение, а при валидации ситуация обрабатывается внутри метода?

Верно. Причем исключения эти не должны отлавливаться в коде (разве что для логирования ошибки), приложению в этом случае нужно дать упасть (fail-fast прицнип). Более подробно на тему исключений: habrahabr.ru/post/263685

Если внутри GetById проверить OrganizationId > 0, это будет контракт или валидация?

В целом ничего не мешает обозначить это как контракт, но с точки зрения best practices контрактами лучше всего помечать значимые с точки зрения модеолирования условия. К примеру то, что юзера нельзя удалить если он уже удален — значимое условие и дает разработчику важную информацию о доменной модели приложения. Еще пример:

public class Organization : Entity
{
    public void ProvisionUser(User user, Subscription subscription)
    {
        Contracts.Require(UsersInternal.Contains(user));
        Contracts.Require(SubscriptionsInternal.Contains(subscription));
        Contracts.Require(subscription.SeatsRemaining > 0);
        Contracts.Require(subscription.IsProvisionable);
        Contracts.Require(!user.IsProvisionedTo(subscription));

        subscription.AddSeat(user);
        user.AddSeat(subscription);
    }
}

Здесь мы даем кучу информации о том, какие условия должны быть соблюдены, чтобы подписать юзера на subscription, клиент этого кода должен быть ответственен за их выполнение перед вызовом ProvisionUser.

Заметил, что я не ответил на этот вопрос:
Чем технически различаются контракты и валидация?

Технически разницы нет. Весь инструментарий поверх контрактов — опционален. Разница в том, как трактовать результат невыполнения условия. В случае с контрактами невыполнение условия — это всегда ошибка в приложении, с точки зрения валидации, — обычное дело, которое можно выводить юзеру в качестве ошибки.
Ваш DeleteUser() это метод внутренний или же он вызывается в пользовательском коде?
Это часть публичного API одного из классов доменной модели.
ОК.
Другими словами, Вы называете предусловия — контрактами?
Есть книга «Touch of Class» и там очень хорошо про предусловия, постусловия, инварианты.
Да, под предусловиями я имею ввиду именно предусловия контрактов. Я выделяю предусловия (и оставляюю за скобками инварианты и постусловия), т.к. предусловия обычно путают с валидацией приходящих извне данных, с постусловиями и инвариантами в этом плане проще.

Конкретно эту книгу Мейера я не читал, но вообще первоисточник моих знаних о контрактах именно Мейер, конкретно эта его книга: www.amazon.com/Object-Oriented-Software-Construction-CD-ROM-Edition/dp/0136291554
Sign up to leave a comment.

Articles