Перейти к содержанию

Абстракция: Мышление разработчика

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

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

Что такое "абстракция"?

В общем смысле, "абстрагироваться" означает примерно "определить, что такое что-то для кого-то, игнорируя всю нерелевантную информацию", и это определение ("что-то") называется абстракцией.

Абстракции иногда синонимично называются "семантикой".

Обратите внимание, что некоторые люди могут дать другое определение "абстракции", например, "абстрактная сущность, общая для нескольких объектов". Вот почему я разделяю это определение на две части: "абстрактная природа" определяется как абстракция; "общая для нескольких объектов" определяется как "стандарты", что будет рассмотрено в следующем разделе.

Исходя из данного определения, возникает несколько важных вопросов при абстрагировании чего-либо:

  1. Что представляет собой абстрагируемый "объект"?
  2. Кто этот "кто-то"? Как он/она/оно будет взаимодействовать с "объектом"?
  3. Что это за "объект" с точки зрения этого "кто-то"?
  4. Какая информация является релевантной? Какая информация нет? То есть, что этот "кто-то" должен знать?

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

Абстракция предназначена не только для других людей; иногда (на самом деле, в большинстве случаев) аудиторией может быть сам разработчик, создающий и реализующий абстрагируемый "объект".

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

Пример абстрагирования

Абстрагированная машина Конкретная машина

Когда вы спешите утром и видите автомобиль, что приходит вам первым на ум? "Я могу водить эту штуку", или шасси, двигатель, шины и бак для топлива?

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

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

  • Цель абстрагирования: Автомобиль.
  • Целевая аудитория: Вы.
  • Что это за "что-то" (абстракция): Что-то, что вы можете использовать для езды по дорогам и быстрого перемещения в любое место.
  • Релевантная информация: Вы можете управлять этой вещью. Она быстрая.
  • Нерелевантная информация: Она состоит из двигателя, топливного бака, шасси и т. д. Она длинна 4,6 метров и высота 1,6 метра, с максимальной мощностью двигателя 140 лошадиных сил. И так далее.

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

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

  • Цель абстрагирования: Автомобиль.
  • Целевая аудитория: Рабочие автомобильного завода.
  • Что это за "что-то" (абстракция): Что-то из двигателя, топливного бака, шасси и остальных деталей.
  • Релевантная информация: Внутренняя структура автомобиля.
  • Нерелевантная информация: Как водить автомобиль.

Как вы видите, абстракция зависит от целевой аудитории. По мере изменения целевой аудитории, изменяется определение цели абстрагирования, и ранее релевантная/нерелевантная информация может стать нерелевантной/релевантной.

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

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

Термины и фразы, связанные с абстракцией

В мире разработки вы встретитесь с некоторыми терминами или фразами, связанными с абстракцией. Вот значения некоторых из них:

Абстракция

В зависимости от сценария "абстракция" может иметь 3 различных значения:

  • Первое значение - "абстрактное определение" объекта, как определено в этом разделе. Основное значение этого определения - "как что-то выглядит для кого-то", но "как что-то выглядит" может быть простым или сложным в зависимости от этого "кто-то";
  • Второе значение - "упрощенное определение объекта, созданное путем скрытия нерелевантных деталей". Это значение подчеркивает, что "абстракция" - это упрощенное описание, скрывающее детали.
  • Третье значение - "антиречийный стандарт, общий для множества объектов"; основное значение этого определения - это то, что абстракция применима ко многим объектам.

Абстракция над

"Абстракция над A" означает, что A является целью абстракции, то есть "что-то", от которого создается абстракция и к которому она применяется.

Абстрагироваться от

Отвлечься от A означает скрыть нерелевантные детали при создании абстракции; A выступает в качестве этих "нерелевантных деталей". Пример: "Языки программирования отвлекают настоящие детали аппаратного обеспечения".

Высоко/низкоуровневая абстракция

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

Например, если цель абстрагирования - это автомобиль, высокоуровневая абстракция может быть "что-то, что можно водить"; низкоуровневая абстракция может быть "что-то, что имеет двигатель, шасси и некоторые колеса" (да, это тоже абстракция. Так как каждый автомобиль с двигателем на топливе имеет двигатель, шасси и некоторые колеса, и это определение скрывает внутреннее устройство двигателя, шасси и т. д., его можно рассматривать как "абстрактный и общий" в каком-то смысле).

Как выглядит абстрагирование в мире разработчика?

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

Вот фрагмент исходного кода из KonnyakuGPT, генератора субтитров аниме на основе искусственного интеллекта (не обязательно разбираться в коде):

def simple_split_subtitles(subtitles: Sequence[srt.Subtitle], max_duration: datetime.timedelta) -> List[srt.Subtitle]:
    """Разделяет слишком длинные субтитры.

    Схема разделения проста; предложения вероятно будут разбиты на части.

    Args:
        subtitles (Sequence[srt.Subtitle]): Исходные субтитры.
        max_duration (float, необязательно): Максимальная продолжительность каждого выходного субтитра в секундах. По умолчанию 10.
    """

    new_subtitles = []
    for subtitle in subtitles:
        remaining_text = subtitle.content
        current_start = subtitle.start
        splitted_subtitles = []

        while len(remaining_text) > 0:
            expected_text_length = math.floor(max_duration / (subtitle.end - current_start) * len(remaining_text))
            actual_text_length = min(expected_text_length, len(remaining_text))
            item_text = remaining_text[:actual_text_length]
            item_duration = len(item_text) / len(remaining_text) * (subtitle.end - current_start)

            splitted_subtitles.append(srt.Subtitle(
                index=len(new_subtitles) + len(splitted_subtitles),
                start=current_start,
                end=current_start + item_duration,
                content=item_text
            ))

            remaining_text = remaining_text[actual_text_length:]
            current_start += item_duration

        new_subtitles += splitted_subtitles

    return new_subtitles

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

Вы могли заметить, что в начале есть некоторый текст, читаемый человеком, а именно следующий:

"""Разделяет слишком длинные субтитры.

Схема разделения проста; предложения вероятно будут разбиты на части.

Args:
    subtitles (Sequence[srt.Subtitle]): Исходные субтитры.
    max_duration (float, необязательно): Максимальная продолжительность каждого выходного субтитра в секундах. По умолчанию 10.
"""

Такой текст называется "докстринг", который, как следует из его названия, предоставляет документацию для функции. Такой докстринг служит абстракцией для пользователя функции, поскольку он включает и только то, что пользователь должен знать: что делает функция и как ее использовать. Остальная часть функции, то есть все после докстринга - это все нерелевантно для пользователя, даже если это логический код, который позволяет функции работать. Пользователь должен знать только, как использовать функцию; ему не важно, как функция работает внутренне.

Абстракция является очень важной в этом сценарии, потому что она позволяет пользователю функции быстро понять только те вещи, которые ему нужно понять. Без докстринга единственный способ узнать, что делает функция - это прочитать и понять код. Хотя это возможно, это гораздо более трудоемко, чем чтение докстринга, и большая проблема заключается в том, что если логический код изменяется, пользователи должны менять способ использования функции, что приведет к множеству изменений в коде. С помощью абстракции, однако, независимо от того, как изменяется логический код, пока он поддерживает интерфейс (то есть то, что функция делает и как ее использовать), определенный в абстракции, пользователи не должны менять способ использования функции.

Абстракции важны не только для пользователей программных систем, но и для тех, кто разрабатывает систему. Когда в программе задействовано много кода (например, KonnyakuGPT имеет примерно ~2,000 строк кода на Python), становится сложно запомнить, что делает каждая часть кода. Без абстракций, таких как докстринги, даже вам самим будет трудно понять код, написанный вами ранее; абстракции облегчают понимание, организацию и поддержку программного обеспечения, над которым вы работаете.

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