Рубрики
Без рубрики

Краткое руководство по чистому коду: Функции

Привет, ребята, Это мой второй пост в серии «Чистый код». В моем первом посте я говорил о том, как N … помеченным новичками, Python, Codequality, функциями.

Привет, ребята,

Это мой второй пост в серии «Чистый код». В моем первом посте я говорил о том, как назвать переменные в «чистом» пути. Теперь я собираюсь поговорить о «чистых функциях» и, как и в прошлый раз, эти точки получены из книги «Чистый код» Роберта С. Мартина.

Ниже приведены некоторые ключевые моменты, которые следует учитывать при написании функций. Итак, начнем.

Функции должны быть маленькими !!!

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

Ниже приведен образец сцепной код, написанный в Python.

def get_product(html_response):
   title = html_response.css('.title').html()
   price = html_response.css('.price').html()
   try:
        price = int(price)
   except ValueError:
        price = None

   sizes_html = list(html_response.css('.product .size').html())
   sizes = [parse_size(html_size) for html_size in sizes_html]
   # ...and so on

Мы могли бы разделить же логику на более мелкие функции, такие как это:

def get_product(html_response):
   title = get_title(html_response)
   price = get_price(html_response)
   sizes = get_product_sizes(html_response)
   # ...and so on

def get_title(html_response):
   return html_response.css('.title').html()

def get_price(html_response):
   price = html_response.css('.price').html()
   try:
        price = int(price)
   except ValueError:
        price = None
   return price

def get_product_sizes(html_response):
   sizes_html = list(html_response.css('.product .size').html())
   sizes = [parse_size(html_size) for html_size in sizes_html]
   return sizes

Таким образом, легче отлаживать и решить код, когда их изменение в целевом сайте.

Блок и отступ

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

Сделай одну вещь! (Принцип одной ответственности)

Функции должны сделать одно. Они должны это делать хорошо. Они должны сделать это только.

Одна функция должна сделать только одну вещь. Если функция делает более одной вещи, функция должна быть разделена в более функции. Это может быть проиллюстрировано с помощью примера ниже:

def generate_weather_report(date):
   data = weather_client.get_date(date)
   if not data:
       logger.error('Error!')
   else:
       report_data = {}
       # logic to get required data into report_data dict.
       store_into_db(report_data)

Эта функция явно делает более одной задач.

  • Получить данные из Интернета.
  • Проверка данных
  • генерировать данные
  • хранить данные в БД

Это может быть восстановлено как следующий код:

data = get_weather_data(date)
is_valid = validate_data(data)
if is_valid:
   report_data = generate_weather_report(data)
   store_into_db(data)
else:
   logger.error('Error!')

def get_weather_data(date):
   return  weather_client.get_date(date)

def generate_weather_report(date):
       report_data = {}
       # logic to get required data into report_data dict.
       return report_data

Таким образом, наша функция Generate_weather_Report делает только одно.

Разделы

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

Список выключателей

Обратите внимание, что в Python нет выключателей в Python. Пример ниже предназначен только к целям объяснения.

Очень трудно сделать маленький Переключатель заявления как цель Переключатель Отчеты должны делать N вещи. Хотя в некоторых случаях Переключатель заявления могут быть избеганы и следует избегать. Например:

def month_index_to_string(index):
   switch index:
       case 1:
           return "January"
       case 2:
           return "February"
       default:
           return "INVALID"
       ...

Может быть написан как:

MONTHS = {
   1: "January",
   2: "February",
   ...
}

def month_index_to_string(index):
   try:
       return MONTHS[index]
   except KeyError:
       return "INVALID"

Используйте описательные имена

Намерение функции должно быть понятно от его имени, и его реализация не должна отклоняться от его имени. Не боитесь использовать имена длинных функций. Идеально имена функций должны начинаться с глагола E.g. get_employers_data , delete_employeree и т.п. Вы можете найти более подробную информацию о именах функций в моем Первый пост Отказ

Функция аргументов

В идеале функция должна иметь нулевые аргументы (функции NILADIC). Далее наступает один (монадический), затем наступает два (дьядические) и, наконец, три (триадические) аргументы функции, которые следует избегать по возможности. Не должны использоваться более трех аргументов (полиадических) функций, если это возможно. Несколько аргументов могут означать, что функция делает более чем одну вещь. Он также тяжело от точки зрения тестирования, чтобы проверить функции со многими аргументами, так как было бы трудно (или почти невозможно), чтобы проверить все комбинации аргументов. Если вам необходимо пройти много данных на функцию, попробуйте отправить эти данные через объект.

def evaluate_person_salary(person_id, hours_worked, hourly_rate, overtime_rate)
   #logic

Это абсолютно зло. Это должно быть написано как:

# person_id, hours_worked, hourly_rate, overtime_rate are data members of the person_data object.
def evaluate_person_salary(person_data, hours_worked):
   #logic

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

Флаг Аргумент

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

Списки аргументов

Иногда мы хотим пройти переменное количество аргументов функции e.g. «{}: {} - {}». Формат (дата, человек, сообщение) Отказ Если эти аргументы обрабатываются одинаково, они считаются одним аргументом ( список в этом случае).

Не иметь побочного эффекта

Одна функция должна сделать только одну вещь без других побочных эффектов. Иногда мы думаем, что наша функция делает только одну вещь Но на самом деле это делать больше, чем одно, и эти другие вещи – это его побочные эффекты. Рассмотрим этот пример ниже:

def check_password(username, password):
   if authenticate_user(username, password):
       return True
   else:
       return False
...
def authenticate_user(username, password):
   if User.objects.get(username=username).check_password(password):
       login(username)
       return True
   return False

Здесь кажется, что check_password делает только одну вещь, проверяю пароль, но когда мы видим в определении uptedicity_user. Мы узнаем, что он также вошел в систему пользователя.

Степень правило

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

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

Не повторяйте себя

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

Я должен был использовать этот подход совсем недавно, когда я писал несколько тестовых случаев для некоторых проектов. Процесс установки для тестовых случаев был в основном одинаковым, поэтому я решил сделать базовый класс с Настройка функция, а затем унаследовать другие тестовые случаи из него. Таким образом, мне не нужно было повторять себя для всех испытаний. Абстрактный код Настройка Функция описана ниже. Вы заметите Степень подход тоже. Вам не нужно снова двигаться вверх и вниз и снова, чтобы понять код.

class SampleTestsBaseClass(TestCase):
   """Base class for all test cases of "Sample" module."""

   def setUp(self):
       """Setup all test data required for testing any of the test cases. """
       super(SampleTestsBaseClass, self).setUp()
       self.topic = self._create_topic()
       self.course = self._create_course()
       self.team = self._create_team(self.course.id, topic_id=self.course.teams_topic['id']))
       self.user = self._create_user()
       self.team_membership = self._create_team_membership(self.team, self.user)

   def _create_topic(self):
       """ Return a topic dict. """
       topic = {u'name': u'Topic', u'description': u'The best topic!', u'id': u'0', 'url': 'example.com/topic/0'}
       return topic

   def _create_course(self, **kwargs):
       """ Create and return a course with test data """
       course = CourseFactory.create(kwargs)
       return course

   def _create_team(self, course_id, topic_id):
       """ Create a CourseTeam for provided course_id and topic_id
       """
       team = CourseTeamFactory.create(
           course_id=course_id,
           topic_id=topic_id,
           name='Test Team',
           description='Testing Testing Testing...'
       )
       return team

   def _create_user(self, username, password, **kwargs):
       user = UserFactory.create(username=username, password=password, **kwargs)
       return user

   def _create_team_membership(self, team, user):
       """Create a team membership object that is responsible for joining of a user in a team.
       """
       membership = CourseTeamMembershipFactory.create(team=team, user=user)
       return membership

# Now inherit the test cases from the above base class.
class Module1TestCase(SampleTestsBaseClass):
   ...

class Module2TestCase(SampleTestsBaseClass):
   ...

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

Заключение

Функции являются основными строительными блоками любой системы. Это глаголы системы, в то время как классы являются существительными. Этот пост был о написании функций таким образом, чтобы это было легко читать, чтобы понять, поддерживать и рефакторировать. Функции должны быть реализованы при сохранении Сухой (Не повторяйте себя) Принцип в виду. Следуя приведенным выше принципам и практике, ваши функции будут описательными, чистыми и красиво организованными.

Оригинал: “https://dev.to/danialmalik/a-brief-guide-to-clean-code-functions-104h”