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

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

20 октября 2022 г.

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

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

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

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

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


Code Smell 116 — переменные, объявленные с помощью 'var'

Var, Let, Const: все они одинаковы, не так ли?

<цитата>

TL;DR: разумно выбирайте имена переменных, область действия и изменяемость.

Проблемы

Решения

  1. Объявляйте const все переменные, если вам не нужно их изменять.

Контекст

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

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

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

Пример кода

Неверно

var pi = 3.14
var universeAgeInYears = 13.800.000.000

pi = 3.1415 // no error
universeAgeInYears = 13.800.000.001 // no error

Правильно

const pi = 3.14 //Value cannot mutate or change 
let universeAgeInYears = 13.800.000.000 //Value can change

pi = 3.1415 // error. cannot define
universeAgeInYears = 13.800.000.001 // no error

Обнаружение

  • [x] Руководство

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

Теги

  • Изменчивость
  • JavaScript

Заключение

Удобочитаемость всегда очень важна.

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

Отношения

Code Smell 86 — Изменяемые массивы констант

Подробнее


<цитата>

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

Брайан Гетц

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


Code Smell 117 — Нереалистичные данные

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

<цитата>

TL;DR: используйте реальные сценарии и реальные данные (когда это возможно)

Проблемы

  • Бибекция Нарушение
  • Плохие сценарии использования
  • Читаемость

Решения

  1. Заменить тестовые данные на реальные.
  2. Используйте MAPPER для сопоставления реальных объектов и реальных данных.

Контекст

В прошлом разработчики подделывали данные домена.

Мы сочли Hello Word хорошей практикой и протестировали ее на абстрактных данных. .

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

С помощью методов биекции и MAPPER, DDD и TDD, приемочное тестирование пользователей стало более важным.

Используя методологии Agile, нам нужно провести тестирование на реальных данных.

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

Пример кода

Неверно

class BookCartTestCase(unittest.TestCase):
    def setUp(self):
        self.cart = Cart()

    def test_add_book(self):
       self.cart.add_item('xxxxx', 3, 10)
        #This is not a real example

       self.assertEqual(self.cart.total, 30, msg='Book Cart total not correct after adding books')
       self.assertEqual(self.cart.items['xxxxx'], 3, msg='Quantity of items not correct after adding book')

    def test_remove_item(self):
        self.cart.add_item('fgdfhhfhhh', 3, 10)
        self.cart.remove_item('fgdfhhfhrhh', 2, 10)    
        #We made a typo since example is not a real one
        self.assertEqual(self.cart.total, 10, msg='Book Cart total not correct after removing book')
        self.assertEqual(self.cart.items['fgdfhhfhhh'], 1, msg='Quantity of books not correct after removing book')

Правильно

class BookCartTestCase(unittest.TestCase):
    def setUp(self):
        self.cart = Cart()

    def test_add_book(self):
       self.cart.add_item('Harry Potter', 3, 10)

       self.assertEqual(self.cart.total, 30, msg='Book Cart total not correct after adding books')
       self.assertEqual(self.cart.items['Harry Potter'], 3, msg='Quantity of items not correct after adding book')

    #We don't reuse same example. 
    #We use a new REAL book
    def test_remove_item(self):
        self.cart.add_item('Divergent', 3, 10)
        self.cart.remove_item('Divergent', 2, 10)    
        self.assertEqual(self.cart.total, 10, msg='Book Cart total not correct after removing book')
        self.assertEqual(self.cart.items['Divergent'], 1, msg='Quantity of books not correct after removing book')

Обнаружение

  • [x] Руководство

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

Исключения

В некоторых доменах и в соответствии с законодательством мы не можем использовать реальные данные.

Мы должны подделать его с помощью значимых данных.

Теги

  • Тестирование

Заключение

Комментарии к коду — это запах кода.

Чтение тестов — единственный способ узнать, как работает программа.

Нам нужно быть более точными в наших тестах.

Отношения

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

Подробнее

Кредиты

Фото Натальи Хофманн на Unsplash

Спасибо Кертису Эйнсманну


<цитата>

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

Альберт Эйнштейн

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


Код Запах 118 — Возврат False

Неудобно проверять, возвращает ли логическое условие логическое значение

<цитата>

TL;DR: не возвращайте явные логические значения. Большинство логических значений — это запахи кода.

Проблемы

  • Декларативность
  • Код ниндзя
  • Внедрение решений

Решения

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

Контекст

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

Программисты склонны возвращать случайные имплементационные решения вместо реальных бизнес-правил.

Пример кода

Неверно

function canWeMoveOn() {
  if (work.hasPendingTasks())
    return false;
  else
    return true;
}

Правильно

function canWeMoveOn() {
  return !work.hasPendingTasks();
}

Обнаружение

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

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

Теги

  • логическое значение

Заключение

Остерегайтесь возврата логических значений.

После возврата вам понадобится оператор If, который также является запахом кода. р>

Отношения

Code Smell 115 – вернуть True< /p>

Code Smell 101 — Сравнение с логическими значениями

Code Smell 24 — Логические приведения

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

Code Smell 102 – код стрелки< /p>

Code Smell 51 — Двойное отрицание

Подробнее

Кредиты

Фото: Морган Хаузел на Unsplash

Спасибо Нико К. за это предложение.


<цитата>

Совсем не важно, чтобы все получилось правильно с первого раза. Крайне важно сделать все правильно в последний раз.

Эндрю Хант

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


Код Запах 119 — Лестничный код

Вложенные логические условия выражают бизнес-правило. Не ЕСЛИ

<цитата>

TL;DR: Избегайте проверки логических выражений и возврата явного логического значения.

Проблемы

Решения

  1. Возвращает логическое значение бизнес-формулы.

Контекст

При работе с логическими формулами более читабельно показывать бизнес-логическую формулу, чем ступенчатые логические проверки, за которыми следует возврат явного значения true/false;

Пример кода

Неверно

def is_platypus(self):
    if self.is_mammal():
        if self.has_fur():
            if self.has_beak():
                if self.has_tail():
                    if self.can_swim():
                        return True
    return False

# This is also wrong since it is polluted with IFs and not readable by a biologist
def is_platypus(self):
    if not self.is_mammal():
        return False
    if not self.has_fur():
        return False
    if not self.has_beak():
        return False
    if not self.has_tail():
        return False
    if not self.can_swim():
        return False 
    return True

Правильно

def is_platypus(self):
    return self.is_mammal() && self.has_fur() && self.has_beak() && self.has_tail() && self.can_swim()

# We can even group conditions according to animal taxonomies

Обнаружение

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

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

Теги

  • логическое значение

Заключение

Остерегайтесь возврата логических значений.

После возврата вам понадобится оператор If, который также является запахом кода. р>

Отношения

Code Smell 115 – вернуть True< /p>

Код Smell 118 — Возврат False

Code Smell 101 — Сравнение с логическими значениями

Code Smell 24 — Логические приведения

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

Code Smell 102 – код стрелки< /p>

Code Smell 80 — вложенная попытка/поймать

Подробнее

Кредиты

Фото Юкана Татеиси на Unsplash

Еще раз спасибо Нико К. за это предложение.


<цитата>

Настоящий герой программирования — это тот, кто пишет отрицательный код.

Дуглас Макилрой

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


Code Smell 120 – последовательные идентификаторы

Большинство IDS — это запахи кода. Последовательные идентификаторы также являются уязвимостью

<цитата>

TL;DR: не выставляйте очевидные последовательные идентификаторы.

Проблемы

Решения

  1. Используйте неочевидные ключи.
  2. Используйте темные клавиши или UUID.

Контекст

Идентификаторы представляют собой проблему при работе с объектами домена.

Идентификаторы не существуют в реальном мире, поэтому они нарушают нашу биекцию.

Идентификаторы следует использовать только при раскрытии внутренних ресурсов внешнему миру за пределами системы.

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

Пример кода

Неверно

class Book {
    private Long bookId; // book knows its ID
    private List<Long> authorIds; // book knows author IDs
}

Book harryPotter = new Book(1, {2});
Book cleanCode = new Book(2, {4});
Book donQuixote = new Book(3, {5});

// We can scrape from now on.

Правильно

class Author {    
    // .. Author protocol
}

class Book {    
    private List<Author> authors; // book knows authors
    // No strange behavior. just what a book can do
    // Real books don't know about IDs
    // ISBN is accidental to a book. Readers don't care
}

class BookResource {    
    private Book resource; // The resource knows the underlying book
    private id; // The id is the link we provide to external world
}

Book harryPotter = new Book(new Author('J. K. Rowling'));
Book cleanCode = new Book(new Author('Robert Martin'))
Book donQuixote = new Book(new Author('Miguel Cervantes'));

BookResource harryPotterResource = new BookResource(harryPotter, UUID.randomUUID());                             

// Books don't know they id. Just the resource does

Обнаружение

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

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

Теги

  • Безопасность

Заключение

Если нам нужно показать внутренние объекты внешнему миру, мы должны использовать неочевидные идентификаторы.

Таким образом, мы можем обнаруживать (и блокировать) атаки грубой силы, отслеживая трафик и ошибки 404.. р>

Подробнее

Кредиты

Фото Макс Бендер на Unsplash

Спасибо, @davidkroell, за совет KSUID.


<цитата>

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

Джин Спаффорд

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


И это пока все…

В следующей статье мы расскажем еще о 5 запахах кода!


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