Рубрики
Без рубрики

Превратите Свой Спагетти-код в функции – Часть 1

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

Первоначально опубликовано в моем блоге

Разработчики могут потратить много часов на борьбу с кодом бизнес-правил. Бизнес-правила спагетти делают так, что небольшие изменения необходимо многократно копировать и вставлять во все блоки if/else. Это все равно что пытаться запихнуть слона в Умную машину, когда это должно быть похоже на сборку лего.

Любой, кто работал над “зрелым” набором бизнес-правил, знает, что разобраться в том, что происходит, чрезвычайно сложно. Если запихнуть слона в Умную машину было непросто, то вытащить его оттуда на порядок сложнее. Я собираюсь показать, как сделать вашего умного слона, управляющего автомобилем, немного счастливее.

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

Кроме того, способ инкапсуляции бизнес-правил OO либо в корне неадекватен, либо настолько широко неправильно понимается работающими разработчиками, что общим шаблоном является класс бога который изменяет все, к чему прикасается. Тестирование огромного класса, напичканного спагетти и мутаторами, в лучшем случае сложно, в худшем – невозможно. Отсутствие тестов очень затрудняет развитие без страха.

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

Это научит вас, как распутывать бизнес-правила, чтобы вы могли легко работать с ними.

Удобочитаемость

Глубокая вложенность ухудшает читаемость. Даже когда разработчики хорошо используют вкладки и согласуются с использованием фигурных скобок, примерно на 3-м уровне операторов if/else становится трудно определить, какую конкретную ветку вы читаете.

Это тот, у которого нулевой дочерний объект? Я просто проверю здесь снова null очень быстро

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

Длительные условия, которые проникают глубоко в дочерние или дочерние объекты, также ухудшают читаемость. Заинтересованные стороны никогда не говорят (если только они не подверглись ужасному насилию) что-то вроде:

Если код типа передачи равен 200 и он не находится в зонах 907, 412 или 213, то это запрещено

  1. В этом больше “нет”, чем любит говорить человек
  2. Люди обычно не говорят о кодах.

Они могли бы сказать что-то вроде:

Если это партнерская транзакция, мы разрешаем ее только в партнерских зонах

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

Проверяемость

Корявый код бизнес-правил трудно протестировать. В хитросплетениях глубоко вложенных операторов if/else легко заблудиться, легко забыть ветку, а иногда просто невозможно настроить в тестовом жгуте. Отсутствие тестов означает , что каждое изменение опасно – вы один из неуместных } , или назад > от того, чтобы доставлять вашим пользователям головную боль.

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

Кто знает? Я обещаю, что никто этого не записывал.

Скорость отклика

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

По-моему, ничто так не говорит о том, что нужно ломать кусты, как спускаться с горы, сходить с тропы и пробиваться через Клуб дьявола и рыхлую осыпь –

Ждать. Я не имел в виду ничего такого, что говорит о взломе кустов, как вход в метод и попадание в неправильную вложенную ветку if/else и исправление чего-то, что не было сломано в первую очередь. Или замечать, что 100 строк кода никогда, никогда не выполнялись, потому что они не будут работать. Или любое количество забавных сюрпризов, которые приносят спагеттифицированные бизнес-правила.

Композиционность

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

Стиль спагетти является антикомпозиционным. Копирование-вставка, дублирование кода и искажение инструкций switch – это практически требования к бизнес-правилам, разработанным на основе спагетти. Удачи в повторном использовании чего-то, чтобы добраться до того самого

Пример Плохого Кода

Вот пример стандартной бизнес-логики Java , которая оценивает бизнес-объект ( Business Transfer ) и создает сообщения для возврата пользователю, если он нарушает бизнес-правила:

public static final String checkWidgetTransfer(WidgetTransfer transfer) {
    String businessRuleErrors = "";

    if (transfer.getTransferer().getAccount(transfer.getFromAccount()).getBalance().compareTo(transfer.getAmount()) < 0) {
        businessRuleErrors += "Insufficient balance to transfer ; ";
    }


    if (transfer.getTransferTypeCode().equals("200")) {
        if (!transfer.getAreaCode().matches("907|412|213")) {
            businessRuleErrors += "This area is not a transfer eligible area. ; ";
        } else if (!transfer.getAreaCode().matches("213")) {
            if (transfer.getTransferer().getCategory().equals("D")) {
                businessRuleErrors += "D Category Transferer can only be transferred in transfer area 213. ; ";
            }
        }
    } else if (transfer.getTransferTypeCode().equals("710")) {
        if (!transfer.getAreaCode().matches("574|213|363|510")) {
            businessRuleErrors += "This area is not a transfer eligible area. ; ";
        }
    }


    if (transfer.getTypeCode().equals("I")) {
        if (isBlockSize(transfer)) {
            businessRuleErrors += "Amount is too small for I type transfer. ; ";
        }
        if (isTotalOverCap(transfer)) {
            businessRuleErrors += "This transfer is too large. ; ";
        }
    }

    return businessRuleErrors;
}


public static boolean isBlockSize(WidgetTransfer transfer) {
    return transfer.getAmount().compareTo(1000) < 0;
}


public static boolean isTotalOverCap(WidgetTransfer transfer) {
    return transfer.getAmount().compareTo(1000000) > 0;
}

Приведенный выше пример вдохновлен реальным кодом, работающим в дикой природе. То, что я показываю здесь, упрощено и анонимизировано. Это так же трудно читать, как и оригинал. Для эффективного его чтения требуется знание того, что такое код типа передачи “200” или какие данные являются приемлемыми для различных кодов зоны передачи. Круглые скобки являются вложенными, что делает копирование-вставку (распространенный метод работы с этим стилем кода) опасным. Разработчик не может позволить себе пропустить ни одной фигурной скобки, не вызвав проблем с отладкой.

Смена парадигмы Логического блока

Быстрый способ рефакторинга длинного ветвящегося кода if/else состоит в том, чтобы отказаться от ветвей и elses . Перефразируя каждое бизнес-правило в положительное ограничение, разработчик может проверить, выполняются ли условия ограничения, вместо того, чтобы ходить по ветвящемуся логическому дереву. Этот метод немного увеличивает количество строк, но значительно улучшает читаемость.

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

public static final String checkWidgetTransfer(WidgetTransfer transfer ) {
String businessRuleErrors = "";
Integer balance = transfer.getTransferer().getAccount(transfer.getFromAccount()).getBalance();
Integer transferAmount = transfer.getAmount();
String transferTypeCode = transfer.getTransferTypeCode();
String areaCode = transfer.getAreaCode();
String category = transfer.getTransferer().getCategory();
String typeCode = transfer.getTypeCode();
if (balance.compareTo(transferAmount) > 0) {
    businessRuleErrors += "Insufficient balance to transfer ; ";
}


{
    if (transferTypeCode.equals("200")
            && !areaCode.matches("907|412|213")) {
        businessRuleErrors += "This area is not a transfer eligible area. ; ";
    }
}


if (transferTypeCode.equals("200")
        && areaCode.matches("213")
        && category.equals("D")) {
    businessRuleErrors += "D Category Transferer can only be transferred in transfer area 213. ; ";
}


if (transferTypeCode.equals("710")
        && !areaCode.matches("574|213|363|510")) {
    businessRuleErrors += "This area is not an eligible area. ; ";


}


if (!typeCode.equals("I")
        && !isBlockSize(transfer)) {
    businessRuleErrors += "Amount is too small for I type transfer. ; ";
}


if (!typeCode.equals("I")
        && isTotalOverCap(transfer)) {
    businessRuleErrors += "This transfer is too large. ; ";
}

return businessRuleErrors;
Enter fullscreen mode Exit fullscreen mode

}

Хороший

  • Приведенный выше код гораздо более удобочитаем.
    • Каждое бизнес-правило содержится в своем собственном логическом блоке
    • Все свойства, необходимые для определения того, было ли выполнено условие, имеют имена.
    • Вы можете описать каждое бизнес-правило в письменном виде, и оно очень похоже на английское.
  • Логические блоки небольшие и дискретные.
    • Здесь нет вложенных фигурных скобок, так что вам будет трудно заблудиться в коде.

Плохое

  • Бизнес-знание того, что означают коды, по-прежнему требуется
    • Что такое код типа перевода “200”? В коде этого не сказано, так что, надеюсь, это где-то задокументировано…
  • Отрицательных условных обозначений предостаточно – если (! введите код.равно("I"))

    • Отрицательные условные обозначения немного трудно произнести, и с ними труднее рассуждать, чем с положительными условными обозначениями.
  • Все еще изменяю эти бизнес-сообщения об ошибках

    • Это всего лишь еще одна вещь, которую нужно настроить в модульном тестировании

Что дальше?

Ознакомьтесь с частью II, чтобы узнать, что будет дальше!

Ты увидишь:

  • Как использовать предикаты, чтобы сделать вашу жизнь лучше
  • Использование реальных объектов, а не только их свойств, чтобы сделать вашу жизнь лучше
  • Использование функций и объектов проверки, чтобы сделать вашу жизнь лучше

Мы постараемся посадить этого слона в его умную машину, но в основном мы постараемся сделать вашу жизнь лучше.

Если вам это нравится, посетите мой блог для получения дополнительной информации

Кредиты

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

Спасибо робот для умный автомобиль, обращенный влево

Спасибо Оливер Додд для слон

Спасибо Niels Heidenreich для клубника-мутант

Спасибо Питер Стивенс для Клуб дьявола

Спасибо НАСА, ЕКА, Н. Смит (U. Калифорния, Беркли) и др. и команда наследия Хаббла (STScI/AURA) для туманности Карина

Оригинал: “https://dev.to/monknomo/turn-your-spaghetti-code-into-functions—part-1”