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

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

21 ноября 2022 г.

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

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

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

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

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

Code Smell 126 — Поддельный нулевой объект


Нулевые объекты — отличная альтернатива "Ошибке на миллиард долларов". Иногда они нам не нужны


<цитата>

TL;DR: не злоупотребляйте шаблонами. Даже NullObject.

.Проблемы

  • Пустые классы
  • Загрязнение пространства имен
  • Повторяющееся поведение

Решения

  1. Создайте пустые объекты, создающие экземпляры классов реальных объектов.

Контекст

Шаблон Null Object — отличная альтернатива NULL. и IF (оба кодовые запахи).

Структура шаблона говорит нам о необходимости создания иерархии.

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

Наследование — неправильный способ достижения полиморфизма.

Простым решением является создание реального объекта, который ведет себя как нулевой.

Например: "0" – это нулевой объект чисел.

“(или "") – это пустой объект String

Пустая коллекция — это нулевой объект коллекции.

Пример кода

Неверно

abstract class Address {
    public abstract String getCity();
    public abstract String getState();
    public abstract String getZipCode();
}

// Using inheritance for null objects is a mistake
// We should use interfaces (when available)
public class NullAddress extends Address {

    public NullAddress() { }

    public String getCity() {
        return Constants.EMPTY_STRING;
    }

    public String getState() {
        return Constants.EMPTY_STRING;
    }

    public String getZipCode() {
        return Constants.EMPTY_STRING;
    }

}

public class RealAddress extends Address {

    private String zipCode;
    private String city;
    private String state;

    public RealAddress(String city, String state, String zipCode) {
        this.city = city;
        this.state = state;
        this.zipCode = zipCode;
    }

    public String getZipCode() {
        return zipCode;
    }

    public String getCity() {
        return city;
    }

    public String getState() {
        return state;
    }

}

Правильно

// There are just "addresses"
public class Address {

    private String zipCode;
    private String city;
    private String state;

    public Address(String city, String state, String zipCode) {
    // Looks anemic :(
        this.city = city;
        this.state = state;
        this.zipCode = zipCode;
    }

    public String zipCode() {
        return zipCode;
    }

    public String city() {
        return city;
    }

    public String state() {
        return state;
    }

}

Address nullAddress = new Address(Constants.EMPTY_STRING, Constants.EMPTY_STRING, Constants.EMPTY_STRING);
// we have our null object
// we should NOT assign it to a singleton, static or global
// It behaves like a null object. That's enough
// No premature optimizations

Обнаружение

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

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

Теги

  • Нет

Заключение

Создание классов Null Object иногда является чрезмерным.

Нам нужно создать настоящий объект.

Этот реальный объект никогда не должен быть глобальным< /a>, одиночка или < a href="https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-iv-7sc3w8n">static.

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

Отношения

Code Smell 12 — Null

Code Smell 32 – синглтоны

Code Smell 114 — Пустой класс< /p>

Code Smell 18 — Статические функции

Code Smell 17 — Глобальные функции

Подробнее

Кредиты

Фото Хуана Давилы на Unsplash

Спасибо Эрнану Уилкинсону за идею курса Diseño a la Gorra (на испанском языке)


<цитата>

Все модели ошибочны, но некоторые модели полезны

Джордж Бокс

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


Code Smell 127 — Изменяемые константы

Вы объявляете что-то константой. Но вы можете изменить его.

<цитата>

TL;DR: используйте неизменяемые константы

Проблемы

Решения

  1. Применить изменяемость< /li>
  2. Избегайте констант. Их трудно имитировать в тестах.

Контекст

Мы научились объявлять константы на первом курсе компьютерного программирования.

Как всегда, неважно, постоянно ли что-то.

Важно, чтобы он не мутировал.

Пример кода

Неверно

const DISCOUNT_PLATINUM = 0.1;
const DISCOUNT_GOLD = 0.05;
const DISCOUNT_SILVER = 0.02;

// Since variables are constants we cannot reassign them
const DISCOUNT_PLATINUM = 0.05; // Error

// We can group them
const ALL_CONSTANTS = {
  DISCOUNT: {
    PLATINUM = 0.1;
    GOLD = 0.04;
    SILVER = 0.02;  
  },
};

const ALL_CONSTANTS = 3.14; // Error

ALL_CONSTANTS.DISCOUNT.PLATINUM = 0.08; // NOT AN ERROR. WTF!


const ALL_CONSTANTS = Object.freeze({
  DISCOUNT: 
    PLATINUM = 0.1;
    GOLD = 0.05;
    SILVER = 0.02; 
});

const ALL_CONSTANTS = 3.14; // Error

ALL_CONSTANTS.DISCOUNT.PLATINUM = 0.12; // NOT AN ERROR. WTF!

Правильно

export const ALL_CONSTANTS = Object.freeze({
  DISCOUNT: Object.freeze({
    PLATINUM = 0.1;
    GOLD = 0.05;
    SILVER = 0.02;  
  }),
});

const ALL_CONSTANTS = 3.14; // Error

ALL_CONSTANTS.DISCOUNT.PLATINUM = 0.12; // ERROR

// Code works, but it is coupled and we cannot test it

Class TaxesProvider {
  applyPlatinum(product);
}

// Now we can couple to a interface (the protocol of taxes provider)
// Since class has no setters it is constant an immutable
// And we can replace it on tests

Обнаружение

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

Мы можем выполнить мутационное тестирование, чтобы найти измененные значения.

Теги

  • Константы

Заключение

Важна изменчивость.

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

Отношения

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

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

Code Smell 02 — Константы и магические числа< /а>

Подробнее

Кредиты

На создание этого запаха вдохновил это

Фото Сангхарша Лохакаре на Unsplash


<цитата>

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

Эрик Гамма

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


Code Smell 128 – кодирование не на английском языке

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

<цитата>

TL;DR: придерживайтесь английского языка. Всегда.

Проблемы

  • Полиморфизм
  • Разрыв в культуре
  • Смешанный код
  • Синтаксические ошибки

Решения

  1. Писать на английском
  2. Переименовать понятия домена на английском языке

Контекст

Все языки программирования написаны на английском языке.

Если не считать нескольких неудачных экспериментов в 90-х годах, все современные языки используют английский для своих примитивов и фреймворков.

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

Это справедливо для современных языков программирования.

Я не являюсь носителем английского языка.

Мой код (кажется) на английском.

Пример кода

Неверно

const elements = new Set();

elements.add(1);
elements.add(1);

echo elements.size() yields 1 
// This is the standard set

var moreElements = new MultiConjunto();
// We defined a multiset in Spanish
// because we are extending the domain

moreElements.agregar('hello');
moreElements.agregar('hello');
// 'agregar' is the Spanish word for 'add'

echo moreElements.size() yields 2 // Since it is a multiset

// elements and moreElements are NOT polymorphic
// I cannot exchange their implementation

Правильно

const elements = new Set();

elements.add(1);
elements.add(1);

echo elements.size() yields 1 
// This is the standard set

var moreElements = new MultiSet();
// We defined a multiset in English

moreElements.add('hello');
moreElements.add('hello');

echo moreElements.size() yields 2 // Since it is a multiset

// elements and moreElements are polymorphic
// I can exchange their implementation anytime

Обнаружение

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

Большинство IDE и линтеров имеют тезаурус.

Мы можем искать иностранные слова.

Теги

  • Читаемость

Заключение

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

Даже при сопоставлении ваших реальных объектов используйте простой английский язык.

Подробнее

Кредиты

Фото Анны Вандер Стел на Скрыть


<цитата>

Язык программирования — это инструмент, оказывающий глубокое влияние на наши мыслительные привычки.

Эдсгер Дейкстра

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


Code Smell 129 — Структурная оптимизация

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

<цитата>

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

Проблемы

  • Читаемость
  • биекция и MAPPER нарушения
  • Преждевременная оптимизация

Решения

  1. Покройте свои сценарии тестами.
  2. Создайте читаемый (и, возможно, неэффективный) код.
  3. Проведите реальный тест с реальными пользовательскими данными. (Нет, итерация кода 100 000 раз может оказаться нереальным вариантом использования).
  4. Если у вас есть убедительные данные, вам нужно улучшить обнаруженные узкие места с помощью сравнительного анализа, используя принцип Парето.
  5. Атакуйте 20 % самых серьезных проблем, вызывающих 80 % низкой производительности.

Контекст

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

Мы склонны переоценивать (возможные) проблемы с производительностью и недооценивать удобочитаемость кода и срок службы программного обеспечения.

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

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

Пример кода

Неверно

for (k = 0; k < 3 * 3; ++k) {
     i = Math.floor(k / 3);
     j = k % 3;
     console.log(i + ' ' +  j);
  }

// This cryptic piece of code iterates a
// two dimensional array
// We don't have proofs this will be useful
// In real contexts

Правильно

for (innerIterator = 0; innerIterator < 3; innerIterator++) {
  for (outerIterator = 0; outerIterator < 3; outerIterator++) {
   console.log(innerIterator + ' ' +  outerIterator);
  }
 }

// This is a readable double for-loop
// 3 is a small number
// No performance issues (by now)
// We will wait for real evidence

Обнаружение

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

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

Нам может показаться, что код труднее читать.

Теги

  • Преждевременная оптимизация

Заключение

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

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

Отношения

Code Smell 06 — Слишком умный программист

Code Smell 20 — Преждевременная оптимизация

Подробнее

Кредиты

Фото Присциллы Дю Приз на Скрыть


<цитата>

Оптимизм — это профессиональный риск программирования: обратная связь — это лечение.

Кент Бек

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


Code Smell 130 — AddressImpl

Приятно видеть класс, реализующий интерфейсы. Лучше понимать, что он делает

<цитата>

TL;DR: называйте свои классы именами реальных концепций.

Проблемы

Решения

  1. Найдите правильное имя с помощью MAPPER

Контекст

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

Нам следует тщательно выбирать имена.

Пример кода

Неверно

public interface Address extends ChangeAware, Serializable {

    /**
     * Gets the street name.
     *
     * @return the street name
     */
    String getStreet();
    // ...
}

// Wrong Name - There is no concept 'AddressImpl' in real world
public class AddressImpl implements Address {
    private String street;
    private String houseNumber;
    private City city;
    // ..
}

Правильно

// Simple
public class Address {
    private String street;
    private String houseNumber;
    private City city;
    // ..
}


// OR
// Both are real-world names
public class Address implements ContactLocation {
    private String street;
    private String houseNumber;
    private City city;
    // ..
}

Обнаружение

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

Поскольку это запах именования.

Мы можем искать с помощью регулярных выражений и переименовывать эти понятия.

Теги

  • Именование

Заключение

Нам следует выбирать имена классов в соответствии с существенной биекцией, а не следовать случайной реализации.

Не называйте « в своих интерфейсах.

Отношения

Code Smell 65 — Переменные, названные в честь типов

Code Smell 38 — Абстрактные имена

Подробнее

Кредиты

Фото Полы Хейс на Unsplash


<цитата>

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

Роберт С. Мартин

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


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

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


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