Сравнение булевых значений и смешение ответственностей


Исходный код

functiongetError() {
        var error = false;
        if (isNaN($('client_sum').value) || $('client_sum').value <= 0) {
            $('error_op').innerHTML = "Только число больше нуля";
            error = true;
        } else {
            $('error_op').innerHTML = "";
        }
        if ($('comment').value == "") {
            $('error_op2').innerHTML = "Введите примечание";
            error = true;
        } else {
            $('error_op2').innerHTML = "";
        }
        if (error == true) returnfalse;
    }

Что не так в этом коде

Возвращаемое значение

Тут сразу три ошибки:

  1. Непонятный набор возвращаемых значений: в случае наличия ошибки будет возвращена false, а при отсутствии ошибки — undefined. При этом второй вариант не задан в явном виде, что плохо.
  2. При сравнении используется нестрогий оператор, что в JavaScript является плохим тоном.
  3. Переменные, принимающие булевы значения, нет необходимости сравнивать с другими булевыми значениями, так как можно использовать непосредственно сами значения:
return !error;

Большое количество ответственностей в одном методе

В этом примере код функции getError делает сразу много вещей:

  1. Получает значения из полей формы
  2. Валидирует значения
  3. Записывает результаты валидации в форму
  4. Возвращает признак наличия ошибки.

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

Для более-менее крупных проектов подобный стиль недопустим. Все ответственности должны быть отделены друг от друга. Мы должны быть готовы к тому, что данные будут поступать и из других источников, не только из полей формы, и их тоже нужно будет валидировать. Соответственно, нам может понадобиться отдельно провести валидацию без вывода куда-либо сообщений об ошибках. Может понадобиться запустить валидацию отдельного поля или при невалидности какого-то специфического поля запускать специальный wizard с подсказками по исправлению ошибки.

Чтобы быть готовым к любоому развитию событий, для реализации полей форм должны использоваться отдельные компоненты с набором общих методов, например, таких:

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

В качестве демонстрации приведу фрагменты кода компонентов «поле» и «форма», касающиеся влаидации.

classField {
    constructor(id, validationFunction) {
        this.$field = document.getElementById(id);
        this.$input = this.$field.getElementsByTagName('input')[0];
        this.$errors = this.$field.getElementsByClassName('errors')[0];
        this.validationFunction = validationFunction;
    }
    getValue() {
        returnthis.$input.value;
    }
    isValid() {
        this.validate();
        return _.isEmpty(this.errors);
    }
    validateAndShowErrors() {
        this.validate();
        this.showErrors();
    }
    validate() {
        this.errors = this.validationFunction(this.getValue());
    }
    showErrors() {
        this.$errors.innerHTML = this.errors.join('<br>');
    }
}
functionvalidateClientSum(clientSum)
{
    if (isNaN(clientSum) || clientSum <= 0) {
        return ['Только число больше нуля'];
    }
}
functionvalidateComment(comment)
{
    if (comment === '') {
        return ['Необходимо заполнить комментарий'];
    }
}
classForm {
    constructor() {
        this.clientSum = newField('client_sum', validateClientSum);
        this.comment = newField('comment', validateComment);
    }
    onSubmit(event) {
       this.validateAndShowErrors();
       if (!this.isValid()) {
           event.preventDefault();
        }
    }
    isValid() {
        returnthis.clientSum.isValid() && this.comment.isValid();    
    }
    validateAndShowErrors() {
        this.clientSum.validateAndShowErrors();
        this.comment.validateAndShowErrors();
    }
}

Теория