Как найти вонючие части вашего кода [Часть XXXI]
17 февраля 2023 г.Запахи кода — это классика.
Это пахнет, потому что, вероятно, есть много случаев, когда его можно отредактировать или улучшить.
n Большинство этих запахов являются лишь намеками на то, что что-то может быть не так. Следовательно, их не обязательно исправлять как таковые… (Тем не менее, вы должны изучить это.)
Пахнет предыдущим кодом
Вы можете найти все предыдущие запахи кода (Часть I – XXX) здесь
n Продолжим...
Code Smell 151 — Код с комментариями
Новички боятся удалять код. И многие пожилые тоже.
<цитата>TL;DR: не оставляйте закомментированный код. Удалите его.
Проблемы
- Читаемость
- Мертвый код
- Отсутствие охвата
- Отсутствие контроля версий
Решения
- Удалить закомментированный код
- Внедрить контроль версий исходного кода
Рефакторинг
Рефакторинг 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: не меняйте семантику кода, чтобы пропустить код.
Проблемы
- Читаемость
- Нераскрытие намерений
Решения
- Если вам нужен временный хак, сделайте это явным
- Полагайтесь на свою систему управления версиями
Контекст
Изменение кода с помощью временного хака – очень плохая практика для разработчиков.
Мы можем забыть некоторые временные решения и оставить их навсегда.
Пример кода
Неверно
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: имена должны быть достаточно длинными. Больше нет.
Проблемы
- Читаемость
- Когнитивная нагрузка
Решения
- Используйте имена, связанные с MAPPER .
Контекст
Мы использовали очень короткие имена в 50-х и 60-х годах из-за нехватки места и времени.
В современных языках это уже не так.
Иногда мы слишком волнуемся.
Именование — это искусство, и мы должны быть осторожны с ним.
Пример кода
Неверно
PlanetarySystem.PlanetarySystemCentralStarCatalogEntry
// Redundant
Правильно
PlanetarySystem.CentralStarCatalogEntry
Обнаружение
- [x] Полуавтоматический
Наши линтеры могут предупредить нас слишком длинными именами.
Теги
- Раздувание
- Именование
Заключение
Не существует жестких правил относительно длины имени.
Просто эвристика.
Отношения
Подробнее
- Что такое имя? — Часть I: Поиски
- Что такое имя? — Часть II: Реабилитация
- Длинные и короткие названия
Кредиты
Фото Эмре Караташ на Unsplash
<цитата>
Многие люди склонны смотреть на стили и языки программирования как на религии: если вы принадлежите к одной, вы не можете принадлежать к другой. Но эта аналогия — еще одно заблуждение.
Никлаус Вирт
Великие цитаты о разработке программного обеспечения
Code Smell 154 — Слишком много переменных
Вы отлаживаете код и видите слишком много объявленных и активных переменных
<цитата>TL;DR: переменные должны быть как можно более локальными
Проблемы
- Читаемость
- Повторное использование кода
Решения
- метод извлечения
- Удалить неиспользуемые переменные
Рефакторинг
Рефакторинг 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: не блокируйте себя сортированным образом.
Проблемы
- Индетерминизм
- Узкое место в производительности
Решения
- Дождитесь всех обещаний одновременно.
Контекст
Мы слышали о семафорах, когда изучали операционные системы.
Мы должны дождаться выполнения всех условий независимо от заказа.
Пример кода
Неверно
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 запахов кода.
Оригинал