Clean ABAP — Как сделать код чистым, прочитав рекомендации к единому стилю? Часть 3

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

Предыдущая часть | Следующая часть

Тезисно по 2-ой главе книги. Подглавы:

  • 2.3. Предпочитайте Объектную ориентации Процедурному программированию
  • 2.4. Отдавайте предпочтение функциональным языковым конструкциям по сравнению с процедурными языковыми конструкциями
  • 2.5. Избегайте устаревших языковых элементов

Предпочитайте Объектную ориентации Процедурному программированию

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

Парадигма программирования ABAP

  • Неструктурированные программы
    Прыгайте свободно и «безумно» с помощью операторов GOTO . ABAP никогда не поддерживал такого рода поведение, которое слишком поощряет нечистый код.
  • Процедурные программы
    Замените goto функциями и областями локальных переменных, которые затрудняют случайный вызов или доступ к неправильной вещи. ABAP начинался как процедурный язык.
  • Объектно-ориентированные программы
    Разрешите создавать экземпляры одной и той же функции несколько раз для разных контекстов, добавляя интерфейсы и наследование сверху. ABAP приняла объектно-ориентированную парадигму в начале 2000-х годов.
  • Функциональные программы
    Удалите состояния и освободите функции от побочных эффектов. Вы можете реализовать некоторые функциональные паттерны в ABAP, но недостающие части, такие как лямбда-функции и потоки, помешают вам полностью принять их.
  • Декларативные программы
    Не перечисляйте, какой шаг нужно сделать один за другим; только опишите целевую картину, которая должна быть достигнута. Хотя сам ABAP не является декларативным, тесно связанный SQL традиционно считается декларативным.

Различие между функциональными группами и классами

Сравнивая процедурную и объектно-ориентированную часть ABAP, можно сказать, что классы похожи на функциональные группы. Проще говоря, представьте себе функциональную группу как CLASS, который является GLOBAL, ABSTRACT, и FINAL. Функции, процедуры форм и глобальные переменные являются его членами, и все они STATIC и PUBLIC.

Нет создания экземпляра

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

Никакого наследства

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

Нет пространства имен для методов

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

Никаких Интерфейсов

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

Слабая подстановка

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

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

Слабая инкапсуляция переменных

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

ASSIGN ('(my_report) gv_global variable) TO .

Нет инкапсуляции метода

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

PERFORM set_buffer_true IN PROGRAM my_ program.

Различия объектно-ориентированного подхода АBAP от других

Существуют два случая, когда способ реализации объектной ориентации ABAP отличается от того, что вы можете знать из других объектно-ориентированных языков программирования, таких как C++, Java или C#. Вы могли бы назвать эти ограничения, но на самом деле эти случаи на самом деле не уменьшают возможности языка, а только делают синтаксис немного более многословным.

Нет перегрузки

Перегрузка означает, что класс предлагает несколько методов с точно таким же именем, но немного разными параметрами. Хотя перегрузка является распространенным шаблоном в Java, ABAP не поддерживает его и обеспечивает, чтобы каждое имя метода встречалось только один раз в классе. Это ограничение чисто синтаксическое и не снижает выразительности языка. Например, ABAP заставит вас отличать метод LOG_STRING от метода LOG_INTEGER, что сделает код менее приятным для чтения, но мы все равно сможем регистрировать как строки, так и целые числа.

Имена интерфейсов становятся частью имен методов

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

В Java, например, если класс Person реализует интерфейс BusinessPartner, который указывает метод getEmail, вы можете написать:

Person alice = new Person(); alice.getEmail();

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

DATA(bob) = NEW person( ). bob->business_partner~get_email( ).

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

Когда нет выбора

В некоторых случаях в ABAP вы не сможете использовать объектную ориентацию для достижения цели. Например, классы не могут обслуживать remote function calls (RFC), и вам придется прибегнуть к функциям RFC.

В этих случаях мы рекомендуем использовать процедурные части программирования ABAP, но убедитесь, что они перенаправляют вызов только на объектно-ориентированный фрагмент кода, например:

FUNCTION check_business partner [...]. DATA(validator) = NEW biz_partner_validator( ). result = validator->validate( business partners ). ENDFUNCTION.

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

Отдавайте предпочтение функциональным языковым конструкциям по сравнению с процедурными языковыми конструкциями

Процедурные языковые конструкции — это конструкции, которые требуют своих собственных ключевых слов, например, в следующих случаях:

DESCRIBE FIELD input LENGTH DATA(length) IN CHARACTER MODE.

Конструкции функционального языка напоминают обычные вызовы методов с любым количеством импортируемых параметров и одним RETURN параметром, например, в следующем примере:

DATA(length) = strlen( input ).

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

  • Более естественно для современных программистов
  • Короче
  • Никаких побочных эффектов
    Например, оператор TRANSLATE my_variable TO UPPER CASE. изменит содержимое переменной, в то время как эквивалентные DATA (uppercase) = to_upper( my_variable ). оставят исходную переменную нетронутой.
  • Встроенные объявления данных
    Например, процедурный способ получения ссылки на объект, GET REFERENCE OF accounts INTO accounts_reference., требует, чтобы вы запомнили больше деталей, таких как слова OF и INTO, которые не добавляют и не изменяют функцию, в то время как эквивалентная функциональная конструкция accounts_reference = REF #( accounts ). требует только запоминания слова REF.
  • Метод вложенности

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

    DATA(harmonized) = condense( to_upper( dirty input ) ).

  • Присваивание значения переменной
    MOVE 'A' TO variable.
    DATA(variable) = A.
  • Преобразование в верхний регистр
    TRANSLATE lowercase TO UPPER CASE.
    DATA(uppercase) = to_upper( lowercase ).
  • Приращение переменных
    ADD 1 TO index.
    index = index +1. " < NW 7.54
  • Создание экземпляра объекта
    CREATE OBJECT object TYPE /dirty/my class.
    DATA(object) = NEW /clean/my_class( ).
  • Заполнение внутренних таблиц
    LOOP AT input INTO DATA(row). INSERT row-text INTO TABLE result. ENDLOOP.
    result = VALUE #( FOR row IN input ( row-text ) ).
  • Поиск строки во внутренней таблице
    READ TABLE value_pairs INTO DATA(line) WITH KEY name = A.
    " if entry must exist
    DATA(line) = value_pairs[ name = 'A' ].
    "if entry can be missing:
    DATA(line) = VALUE #( value_pairs[ name = A ] OPTIONAL )
  • Проверка наличия строки во внутренней таблице
    READ TABLE values TRANSPORTING NO FIELDS WITH KEY name = A. DATA(exists) = xsdbool( sy-subrc = 0 ).

    DATA(exist) = xsdbool( line_exists( values[ name = 'A' ] ) ).
    IF line_exists( values[ name = 'A' ] ).

Избегайте устаревших языковых элементов

Когда вы обновляете свои системы ABAP, убедитесь, что вы проверяете языковые конструкции, которые устарели и теперь считаются устаревшими. Все версии документации, по ключевым словам, ABAP содержат статью под названием Устаревшие языковые элементы, в которой перечислены устаревшие операторы, например: http://s-prs.co/v519004 для SAP NetWeaver 7.54. Вы должны воздерживаться от использования этих утверждений по целому ряду причин:

  • Лучшей читаемости
    Использование более новых форм операторов часто улучшает читабельность вашего кода без какого-либо фактического редизайна. Например, @- экранированные переменные «host» в операторе, немного проясняют, что такое программная переменная и что такое столбец в базе данных.
  • Более простая и безопасная эксплуатация
    Различные конструкции были сделаны устаревшими, потому что они стали не соответствовать современным парадигмам программирования, даже до такой степени, что использование этих конструкций трудно и/или подвержено ошибкам.

    Типичным примером являются внутренние таблицы со строками заголовка, где my_table будет обращаться к строке заголовка таблицы, в то время как только my_table[] будет обращаться к фактическому содержимому таблицы. Даже опытные абаперы неоднократно оказывались в общей ловушке, забывая квадратные скобки и случайно изменяя только строку заголовка, а затем требуя часов поиска причины тонких ошибок, которые это влечет за собой.
  • Постоянное совершенствование
    Устаревшие языковые конструкции больше не получают улучшений, и, таким образом, вы не выиграете от какой-либо будущей оптимизации с точки зрения скорости обработки и потребления памяти. Не отсекайте себя от таких улучшений.
  • Проще для новых коллег
    Устаревшие языковые элементы удаляются из учебных ресурсов ABAP, чтобы новые коллеги, которые недавно изучают язык, вообще не узнавали об устаревшем языке. Как следствие, новые абаперы могут быть не в состоянии начать кодирование сразу, но, возможно, потребуется дополнительное повышение квалификации в старомодных утверждениях, прежде чем безопасный код может быть произведен.

скоро вернусь...

11
Начать дискуссию