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

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

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

Следующие правила помогут в этом.

Используйте TDD

TDD расшифровывается как разработка, управляемая тестированием. Это метод, с помощью которого вы пишете тесты, а не логику.

Рассмотрим следующий псевдокод функции.

if inputNumber = 0
  return inputNumber
else if inputNumber = 1
  return inputNumber * 2
else
  return inputNumber * 10

Чтобы реализовать это с помощью TDD, вы сначала должны написать простой тест с простым утверждением. Например, мы видим, что эта функция должна возвращать 0, если мы передаем 0, поэтому мы должны написать тест, подобный следующему (примечание: я использую для этого JavaScript, но он работает на любом языке).

Теперь вы должны написать логику, чтобы пройти тест. Самый простой способ сделать это - заставить функцию возвращать 0.

Поскольку тест пройден, мы можем взять следующее утверждение, т.е. функция должна вернуть 2, если на входе 1, и написать для этого тест.

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

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

Сделайте это снова, не нарушая других тестов.

И готово.

Вы заметите, что мы изменили способ обработки функцией значения 0. Это важная часть TDD. Каждый раз, когда вы пишете код для прохождения очередного теста, вы реорганизуете его.

TDD можно применять почти всегда, и на самом деле он лучше подходит для более сложных ситуаций.

TDD:

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

Это один из лучших способов быстро написать чистый код.

Избегайте вложенной логики

Вот псевдокод функции, вычисляющей избыточную оплату.

if employee's age < 20
  redundancyPay = 0
else
  if employeeRole = management
    redundancyPay = employeeTerm * (annualSalary * 0.05)
  else
    if employeeTerm <5
      redundancyPay = employeeTerm * (annualSalary * 0.02)
    else if employeeTerm > 10
      redundancyPay = employeeTerm * (annualSalary * 0.04)
    else
      redundancyPay = employeeTerm * (annualSalary * 0.03)

И вот как мы могли бы это написать.

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

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

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

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

Предпочитайте функции с одним параметром и одной обязанностью

Функция с несколькими параметрами пугает. Также обычно существует положительная корреляция между аргументами и сложностью.

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

  • Создайте тип данных для инкапсуляции связанных параметров
  • Подумайте, сколько обязанностей у вашей функции

Для первого пункта отлично подходят языки со строгой типизацией. В общем, четко определенные пользовательские типы данных - верный способ упростить понимание и поддержку вашей программы. Но даже с такими языками, как Python и JavaScript, вы все равно должны предпочесть объекты отдельным свойствам, когда данные связаны, потому что это, по крайней мере, накладывает ярлык на данные в целом и помогает читателям понять, как все сочетается.

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

Функция calculateEmployeeFinancials выполняет несколько задач. Вы можете возразить, что технически это единственная обязанность «расчета финансовых показателей», но ее все же можно разбить на более мелкие детали. Как правило, максимально возможное разбиение функций является оптимальным и требует не больше усилий, чем альтернатива, если вы имеете это в виду с самого начала. Это упрощает понимание и тестирование кода. Вот исправленное решение.

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

Функция buildEmployee, возможно, тоже может быть разбита, но будут моменты, когда вам нужно будет выполнить немного более сложную логику. Идея состоит в том, чтобы разбить его как можно больше, а затем сложить части вместе, как пазл, чтобы построить более сложные процессы.

Остерегайтесь модных инструментов

Это может быть спорным. В большинстве языков есть лаконичные способы написания, но часто лаконичность достигается за счет ясности. Рассмотрим это if заявление.

Этот код занимает 6 строк и выглядит немного неуклюже. Но это понятно. Теперь представьте, что это написано как троичное выражение JavaScript.

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

Тройные числа неплохие. Они могут быть хороши в очень простых ситуациях, например:

Но если что-то сложнее, вы играете с огнем.

Отдавайте предпочтение процедурному программированию

Пользовательские типы данных - это прекрасно, но когда вы прикрепляете к ним поведение, они становятся объектами. Это когда все усложняется.

Объекты - это экземпляры классов. Классы - это наборы свойств и методов. Классы могут владеть объектами других классов, что позволяет им вызывать поведение других объектов в программе. Это уже звучит сложно, но становится намного хуже.

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

Когда у вас возникают подобные ситуации, становится очень трудно следить за ходом программы. Отладка включает в себя попытку визуализировать извилистые виртуальные пути, как в лабиринте. А еще есть наследование. Эх.

В процедурном программировании нет ни одной из этих проблем. Процедурный код просто выполняется шаг за шагом в четкой последовательности. Это не означает, что вы не можете вызывать другие функции, но не существует концепции какой-либо другой «сущности», такой как объект, берущий контроль над выполнением или что-то еще. Это просто шаг за шагом, полностью. За ним намного легче следить, намного легче читать и намного проще отлаживать.

Вот отличное видео об этом. Не смотрите, если вы энтузиаст объектно-ориентированного программирования. Или вообще-то.

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