Как найти ненужные части вашего кода [Часть XLVII]

Как найти ненужные части вашего кода [Часть XLVII]

28 декабря 2023 г.

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

Большинство этих запахов — всего лишь намеки на что-то неладное. Следовательно, их не обязательно исправлять как таковые… (Хотя вам стоит над этим разобраться.)

Запах предыдущего кода

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

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


Код Smell 231 – избыточные данные

Где ваши источники истины?

<блок-цитата>

TL;DR: скажите это только один раз

Проблемы

  • Нарушение принципа «Не повторяйся».
  • Проблемы с согласованностью
  • Удобство обслуживания
  • Тестирование и отладка

Решения

  1. Сохраняйте ответственность за соответствующие объекты и делегируйте их единому источнику достоверной информации.
  2. Контекст

    Принцип «Не повторяйся» (DRY) призывает вас избегать избыточности и дублирования поведения.

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

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

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

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

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

    Пример кода

    Неверно

    class Transfer:
        def __init__(self, amount, income, expense):
            self.amount = amount
            self.income = income
            self.expense = expense
    
    class Income:
        def __init__(self, amount):
            self.amount = amount
            # amount is the same for party and counterparty
    
    class Expense:
        def __init__(self, amount):
            self.amount = amount
    
    transfer_amount = 1000  
    # simplification: should be a money object with the currency
    
    income = Income(transfer_amount)
    expense = Expense(transfer_amount)
    transfer = Transfer(transfer_amount, income, expense)
    
    print("Transfer amount:", transfer.amount)
    print("Income amount:", transfer.income.amount)
    print("Expense amount:", transfer.expense.amount)
    

    Верно

    class Transfer:
        def __init__(self, amount):
            self.amount = amount
            self.income = Income(self)
            self.expense = Expense(self)
    
    class Income:
        def __init__(self, transfer):
            self.transfer = transfer
    
        def get_amount(self):
            return self.transfer.amount
    
    class Expense:
        def __init__(self, transfer):
            self.transfer = transfer
    
        def get_amount(self):
            return self.transfer.amount
    
    transfer_amount = 1000  
    transfer = Transfer(transfer_amount)
    
    print("Transfer amount:", transfer.amount)
    print("Income amount:", transfer.income.get_amount())
    print("Expense amount:", transfer.expense.get_amount())
    

    Обнаружение

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

    Это смысловой запах

    Исключения

    Теги

    Заключение

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

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

    Избыточные данные также увеличивают площадь поверхности для тестирования и отладки.

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

    Отношения

    Код Smell 49 — Кэши

    Отказ от ответственности

    Запахи кода — это мои мнение.

    Кредиты

    Фото Йоргена Холанда на Unsplash


    <блок-цитата>

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

    Майкл Найгард

    https://hackernoon.com/400- Thought-provoking-software-engineering -quotes?embedable=true


    Код Smell 232 – многоразовый код

    Не повторяйтесь. Не повторяйтесь

    <блок-цитата>

    TL;DR: недостающие абстракции можно найти, просматривая повторяющийся код

    Проблемы

    • Нарушение принципа DRY.
    • Удобство обслуживания
    • Эффект пульсации

    Решения

    1. Создайте повторяющийся код
    2. Введите абстракцию
    3. Замените ссылки и укажите новую абстракцию.
    4. Удалить дублирование
    5. Контекст

      Повторяющийся код — признак отсутствия абстракций.

      Это естественно в процессе обучения, поскольку мы не можем предвидеть эти абстракции.

      Пример кода

      Неверно

      def calculate_area(length, width):
          return length * width
      
      def calculate_volume(length, width, height):
          return length * width * height
      

      Верно

      def calculate_area(length, width):
          return length * width
      
      def calculate_volume(length, width, height):
          base_area = calculate_area(length, width)
          return base_area * height
      

      Обнаружение

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

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

      Исключения

      Абстракция должна иметь соответствие зависимости от биекции

      Теги

      • Раздутие

      Заключение

      Повторяющийся код — это проблема и намек на недостающую абстракцию.

      Помните, что вам не нужно избегать копирования и вставки.

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

      Отказ от вырезания и вставки – это ярлык и признак преждевременной оптимизации.

      Отношения

      Code Smell 46 – повторяющийся код

      Code Smell 182 – чрезмерное обобщение< /п>

      Кредиты

      Фото Митчелла Гриста на сайте Unsplash


      <блок-цитата>

      Вставка кода из Интернета в рабочий код похожа на жевательную резинку, найденную на улице.

      Майк Джонсон


      Код Smell 233 — количество коллекций

      Вы считаете коллекции или Collections.count?

      <блок-цитата>

      TL;DR: выбирайте узкие имена

      Проблемы

      • Неправильное название

      Решения

      1. Точно опишите свои коллекции.
      2. Контекст

        Имена имеют большое значение и не должны вводить читателя в заблуждение. f Вы даете имена вещам и теряете объем имени.

        Важно точно определить ожидаемую ссылку на имена.

        Пример кода

        Неверно

        const standardModelParticles = {
          quarks: [
            {
              name: "Up",
              charge: "2/3",
              type: "Quark",
            },
            {
              name: "Down",
              charge: "-1/3",
              type: "Quark",
            },
            // ...
          ],
          leptons: [
            {
              name: "Electron",
              charge: "-1",
              type: "Lepton",
            },
            {
              name: "Muon",
              charge: "-1",
              type: "Lepton",
            },
            // ...
          ],
          gaugeBosons: [
            {
              name: "Photon",
              charge: "0",
              type: "Boson",
            },
            {
              name: "W Boson",
              charge: "±1",
              type: "Boson",
            },
            // ...
          ],
          higgsBoson: [
            {
              name: "Higgs Boson",
              charge: "0",
              type: "Scalar Boson",
            },
          ],
        };
        
        const quarks = standardModelParticles.quarks.length; 
        // Bad name. It does not represent a count
        // But a Collection of things
        

        Верно

        const standardModelParticles = {
        }; // Same as the "Wrong" example
        
        const quarksCount = standardModelParticles.quarks.length; 
        

        Обнаружение

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

        Некоторые линтеры могут проверять типы и имена и делать вывод об ошибке

        Теги

        • Имена

        Заключение

        Берегите свои имена.

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

        Отношения

        Код Smell 163 — Коллекция по имени

        Code Smell 134 – Специализированные бизнес-коллекции

        Код Smell 33 – Сокращения

        Кредиты

        Фото Сэнди Миллар на Unsplash


        <блок-цитата>

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

        Батлер Лэмпсон


        Код Smell 234 – Длинная цепь

        Будьте умны (и ленивы) в условиях низкой производительности

        <блок-цитата>

        TL;DR: Преждевременная оптимизация — это зло. Оптимизация – это хорошо.

        Проблемы

        • Низкая производительность

        Решения

        1. Отсортируйте условия от более быстрого к более медленному.
        2. Контекст

          Читабельность всегда важна, поэтому следует избегать преждевременной оптимизации.

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

          Пример кода

          Неверно

          def is_warm():
              # This is a fast api call to your thermometer
              response = requests.get
                  ("https://iot-device-api.example.com/current_temperature")
              temperature_data = response.json()
          
              return temperature_data.get('temperature', 0) > 25  
          
          def is_weekend():
              # This function checks if today is a weekend
              # based on a slow calendar API call
              response = requests.get
                  ("https://calendar-api.example.com/today")
              calendar_data = response.json()
          
              return calendar_data.get('day_of_week', '').lower() 
                  in ['saturday', 'sunday']
          
          def is_sunny():
              # Very slow function to a low performant weather API call
              response = requests.get
                  ("https://weather-api.example.com/current")
              weather_data = response.json()
          
              return weather_data.get('weather', '') == 'sunny'
          
          is_sunny_value = is_sunny()
          is_warm_value = is_warm()
          is_weekend_value = is_weekend()  
          
          if is_sunny_value and is_warm_value and is_weekend_value:
              # the 3 conditions are always evaluated
              print("Let's go outside!")
          else:
              print("Stay at home.")
          

          Верно

          if is_warm() and is_weekend() and is_sunny():
              # the 3 conditions are evaluated in short circuit 
              # and sorted from fastest to slowest
              # for a fast exit
              print("Let's go outside!")
          else:
              print("Stay at home.")
          

          Обнаружение

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

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

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

          Теги

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

          Заключение

          Найдите узкие места, используя правила Парето.

          Оптимизируйте критически важные разделы кода.

          Отношения

          Code Smell 140 – оценка короткого замыкания

          Code Smell 145 — Взлом при коротком замыкании

          Кредиты

          Фото Ника Абрамса на Unsplash


          <блок-цитата>

          Залогом эффективности является элегантность, а не батальоны особых случаев.

          Джон Бентли и Дуглас Макилрой


          Код Smell 235 – побочные эффекты консоли

          Вы выполняете вычисления и регистрируетесь в одном и том же месте

          <блок-цитата>

          TL;DR: избегайте побочных эффектов

          Проблемы

          • Соединение
          • Тестируемость
          • Повторное использование
          • Композиция функций

          Решения

          1. Разъедините код и избегайте побочных эффектов.
          2. Внедрить место назначения вывода
          3. Контекст

            Вывод на консоль внутри внутренней функции приводит к возникновению связи и побочных эффектов

            Пример кода

            Неверно

            https://gist.github.com/mcsee/c8fcd38572bce8e59bf28ceaede7a055?embedable=true

            Верно

            https://gist.github.com/mcsee/1c4881a54286a827b8fc037fdd89722c?embedable=true

            Обнаружение

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

            Некоторые линтеры предупреждают об этом использовании

            Теги

            - Глобальные значения

            Заключение

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

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

            Отношения

            [Код Smell 17 — глобальные функции])

            Кредиты

            Изображение создано Midjourney


            <блок-цитата>

            Память подобна оргазму. Будет намного лучше, если вам не придется притворяться.

            Сеймур Крей


            На следующей неделе еще 5 запахов.


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