Как найти вонючие части вашего кода [Часть XXXI]

Как найти вонючие части вашего кода [Часть XXXI]

17 февраля 2023 г.

Запахи кода — это классика.

Это пахнет, потому что, вероятно, есть много случаев, когда его можно отредактировать или улучшить.

n Большинство этих запахов являются лишь намеками на то, что что-то может быть не так. Следовательно, их не обязательно исправлять как таковые… (Тем не менее, вы должны изучить это.)

Пахнет предыдущим кодом

Вы можете найти все предыдущие запахи кода (Часть I – XXX) здесь

n Продолжим...


Code Smell 151 — Код с комментариями

Новички боятся удалять код. И многие пожилые тоже.

<цитата>

TL;DR: не оставляйте закомментированный код. Удалите его.

Проблемы

  • Читаемость
  • Мертвый код
  • Отсутствие охвата
  • Отсутствие контроля версий

Решения

  1. Удалить закомментированный код
  2. Внедрить контроль версий исходного кода

Рефакторинг

Рефакторинг 005 — заменить комментарий именем функции

Контекст

При отладке кода мы обычно комментируем код, чтобы увидеть, что происходит.

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

Пример кода

Неверно

function arabicToRoman(num) {
  var decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
  var roman = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
  var result = '';

  for(var i = 0; i < decimal.length; i++) {
    // print(i)
    while(num >= decimal[i]) {
      result += roman[i];
      num -= decimal[i];
    }    
  }
  // if (result > 0 return ' ' += result)

 return result;
}

Правильно

function arabicToRoman(arabicNumber) {
  var decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
  var roman = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
  var romanString = '';

  for(var i = 0; i < decimal.length; i++) {
    while(arabicNumber >= decimal[i]) {
      romanString += roman[i];
      num -= decimal[i];
    }    
  }

 return romanString;
}

Обнаружение

  • [x] Полуавтоматический

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

Теги

  • Комментарии

Заключение

Нам нужно удалить весь закомментированный код.

Отношения

Code Smell 75 — Комментарии внутри метода

Code Smell 05 — Нарушители комментариев

Кредиты

Фото максима бобера на Unsplash< /p>


<цитата>

Не документируйте проблему, исправьте ее.

Атли Бьоргвин Оддссон

Великие цитаты о разработке программного обеспечения


Код Запах 152 — Логический комментарий

Временные взломы могут быть постоянными

<цитата>

TL;DR: не меняйте семантику кода, чтобы пропустить код.

Проблемы

  • Читаемость
  • Нераскрытие намерений

Решения

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

Контекст

Изменение кода с помощью временного хака – очень плохая практика для разработчиков.

Мы можем забыть некоторые временные решения и оставить их навсегда.

Пример кода

Неверно

if (cart.items() > 11 && user.isRetail())  { 
  doStuff();
}
doMore();
// Production code

// the false acts to temporary skip the if condition
if (false && cart.items() > 11 && user.isRetail())  { 
  doStuff();
}
doMore();

if (true || cart.items() > 11 && user.isRetail())  {
// Same hack to force the condition

Правильно

if (cart.items() > 11 && user.isRetail())  { 
  doStuff();
}
doMore();
// Production code

// Either if we need to force or skip the condition
// we can do it with a covering test forcing
// real world scenario and not the code

testLargeCartItems() {}

testUserIsRetail() {}

Обнаружение

  • [x] Полуавтоматический

Некоторые линтеры могут предупреждать нас о странном поведении.

Теги

  • Комментарии

Заключение

Разделение интересов чрезвычайно важно в нашей профессии.

Бизнес-логика и взлом всегда должны быть отделены друг от друга.

Отношения

Code Smell 151 — Код с комментариями

Кредиты

Фото Белинды Фьюингс на странице Скрыть

Спасибо, @Рамиро Рела за этот совет


<цитата>

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

Джон Ромеро

Великие цитаты о разработке программного обеспечения


Code Smell 153 — Слишком длинные имена

Имена должны быть длинными и информативными. Как долго?

<цитата>

TL;DR: имена должны быть достаточно длинными. Больше нет.

Проблемы

  • Читаемость
  • Когнитивная нагрузка

Решения

  1. Используйте имена, связанные с MAPPER
  2. .

Контекст

Мы использовали очень короткие имена в 50-х и 60-х годах из-за нехватки места и времени.

В современных языках это уже не так.

Иногда мы слишком волнуемся.

Именование — это искусство, и мы должны быть осторожны с ним.

Пример кода

Неверно

PlanetarySystem.PlanetarySystemCentralStarCatalogEntry

// Redundant

Правильно

PlanetarySystem.CentralStarCatalogEntry

Обнаружение

  • [x] Полуавтоматический

Наши линтеры могут предупредить нас слишком длинными именами.

Теги

  • Раздувание
  • Именование

Заключение

Не существует жестких правил относительно длины имени.

Просто эвристика.

Отношения

Code Smell 33 — Сокращения

Подробнее

Кредиты

Фото Эмре Караташ на Unsplash


<цитата>

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

Никлаус Вирт

Великие цитаты о разработке программного обеспечения


Code Smell 154 — Слишком много переменных

Вы отлаживаете код и видите слишком много объявленных и активных переменных

<цитата>

TL;DR: переменные должны быть как можно более локальными

Проблемы

  • Читаемость
  • Повторное использование кода

Решения

  1. метод извлечения
  2. Удалить неиспользуемые переменные

Рефакторинг

Рефакторинг 002 — метод извлечения

Контекст

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

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

Пример кода

Неверно

<?

function retrieveImagesFrom(array $imageUrls) {
  foreach ($imageUrls as $index => $imageFilename) {
    $imageName = $imageNames[$index];
    $fullImageName = $this->directory() . "" . $imageFilename;
    if (!file_exists($fullImageName)) {
      if (str_starts_with($imageFilename, 'https://cdn.example.com/')) {
          // TODO: Remove Hardcode
          $url = $imageFilename;
          // This variable duplication is not really necessary 
          // When we scope variables        
          $saveto= "c:temp"."".basename($imageFilename);
          // TODO: Remove Hardcode
          $ch = curl_init ($url);
          curl_setopt($ch, CURLOPT_HEADER, 0);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
          $raw = curl_exec($ch);
          curl_close ($ch);
          if(file_exists($saveto)){
               unlink($saveto);
          }
          $fp = fopen($saveto,'x');
          fwrite($fp, $raw);
          fclose($fp);
          $sha1 = sha1_file($saveto);
          $found = false;
          $files = array_diff(scandir($this->directory()), array('.', '..'));
          foreach ($files as $file){
              if ($sha1 == sha1_file($this->directory()."".$file)) {                         
                  $images[$imageName]['remote'] = $imageFilename;
                  $images[$imageName]['local'] = $file;
                  $imageFilename = $file;
                  $found = true;
                  // Iteration keeps going on even after we found it
              }
          }
          if (!$found){
            throw new Exception('We couldnt find image');
         }
        // Debugging at this point our context is polluted with variables
        // from previous executions no longer needed
        // for example: the curl handler
  }

Правильно

<?php

function retrieveImagesFrom(string imageUrls) {
  foreach ($imageUrls as $index => $imageFilename) {
    $imageName = $imageNames[$index];
    $fullImageName = $this->directory() . "" . $imageFilename;
    if (!file_exists($fullImageName)) {
        if ($this->isRemoteFileName($imageFilename)) {
            $temporaryFilename = $this->temporaryLocalPlaceFor($imageFilename);
            $this->retrieveFileAndSaveIt($imageFilename, $temporaryFilename);
            $localFileSha1 = sha1_file($temporaryFilename);
            list($found, $images, $imageFilename) = $this->tryToFindFile($localFileSha1, $imageFilename, $images, $imageName);
            if (!$found) {
                throw new Exception('File not found locally ('.$imageFilename.'). Need to retrieve it and store it');
            }
        } else {
            throw new Exception('Image does not exist on directory ' . $fullImageName);
        }
    }

Обнаружение

  • [x] Автоматически

Большинство линтеров могут предложить использование длинных методов.

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

Теги

  • Раздувание

Заключение

метод извлечения — наш лучший друг.

Мы должны использовать его часто.

Отношения

Code Smell 03 — Слишком длинные функции< /а>

Code Smell 107 — Повторное использование переменных< /p>

Code Smell 62 — Переменные флага< /p>

Кредиты

Фото Дастана Вудхауса на Unsplash


<цитата>

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

Мартин Фаулер

Великие цитаты о разработке программного обеспечения


Code Smell 155 — Несколько обещаний

У вас есть обещания. Нужно подождать. Подождите их всех

<цитата>

TL;DR: не блокируйте себя сортированным образом.

Проблемы

  • Индетерминизм
  • Узкое место в производительности

Решения

  1. Дождитесь всех обещаний одновременно.

Контекст

Мы слышали о семафорах, когда изучали операционные системы.

Мы должны дождаться выполнения всех условий независимо от заказа.

Пример кода

Неверно

async fetchOne() { /* long task */ }
async fetchTwo() { /* another long task */ }

async fetchAll() {
  let res1 = await this.fetchOne(); 
  let res2 = await this.fetchTwo();
  // they can run in parallel !!  
}

Правильно

async fetchOne() { /* long task */ }
async fetchTwo() { /* another long task */ }

async fetchAll() {
  let [res3, res4] = await Promise.all([this.fetchOne(), this.fetchTwo()]);
  //We wait until ALL are done
}

Обнаружение

  • [x] Полуавтоматический

Это семантический запах.

Мы можем указать нашим линтерам найти некоторые закономерности, связанные с ожиданием промисов.

Теги

  • Производительность

Заключение

Мы должны быть как можно ближе к реальным бизнес-правилам.

Если в правиле указано, что нам нужно ждать ВСЕХ операций, мы не должны навязывать определенный порядок.

Кредиты

Спасибо за идею

Твиттер

Фото Элвина Махмудова на Удалить


<цитата>

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

Дуглас Крокфорд

Великие цитаты о разработке программного обеспечения


Следующая статья: Еще 5 запахов кода.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE