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

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

Рассмотрим этот очень простой пример

let action1Clicked = () => {
  // some common logic same as action2Clicked
  // specific logic
}
let action2Clicked = () => {
  // some common logic same as action1Clicked
  // specific logic
}

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

let commonLogic() => {
  // common logic goes here
}
let action1Clicked = () => {
  commonLogic();
  // some specific logic
}
let action2Clicked = () => {
  commonLogic();
  // some specific logic
}

Если вы считаете, что лучше всего создать новый модуль, то эта статья для вас.

Чрезмерная инженерия

У всего есть предел, иначе будут плохие побочные эффекты.

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

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

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

1. Избавьтесь от дилеммы воображаемых черт

Когда конкретная функция реализуется, могут быть функции, которые могут потребоваться в будущем. Следовательно, вы можете добавить больше гибкости в свой код, добавив больше классов / модулей или методов.

Пример:

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

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

2. Контроль уровня декомпозиции

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

Пример:

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

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

3. Не переусердствуйте с DRY

DRY (Don’t Repeat Yourself) - хороший способ сократить объем дополнительной работы за счет повторного использования существующих вещей или написания более расширяемого кода. А в чистые элементы многоразового использования все не превратить.

Пример:

let someAlgorithm = (myParam_1.. MyParam_n) => {
   // some logic
}

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

Заключение

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

Удачного кодирования! 🥳