Перейти к содержимому

Что такое нотация в программировании

  • автор:

Совершенный код: именование в программировании

Совершенный код: именование в программировании главное изображение

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

В этой статье я разберу наиболее общие правила, принятые в среде разработчиков. Для примеров будет использоваться javascript , но это не принципиально. Рекомендации подходят для всех.

Нотация

Перед тем, как говорить о семантике, давайте посмотрим на синтаксис. Существует несколько популярных нотаций именования:

  • Верблюжья нотация (CamelCase): myClass
  • Змеиная нотация (snake_case): my_const
  • Шашлычная нотация (kebab-case): my-data
  • Особняком стоит Венгерская нотация

В реальности их гораздо больше, хотя многие вышли из обихода и не употребляются, либо употребляются крайне редко (по крайней мере, вряд ли многие помнят COBOL-CASE ).

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

Подписывайтесь на канал Кирилла Мокевнина в Telegram — чтобы узнать больше о программировании и профессиональном пути разработчика

Размер имеет значение

Те, кто сдавал лабораторные по программированию, хорошо помнят, что большинство переменных в них были однобуквенными. Интересный факт состоит в том, что в первых языках программирования идентификаторы были таки односимвольными, как обозначения в математике. Первым языком, судя по всему, который начал использовать слова как идентификаторы, был Лисп. С тех пор (шестидесятые) утекло много воды и использование однобуквенных идентификаторов в современном мире рассматривается как моветон.

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

Сущность-Действие

bed(); // bad sleep(); // good 

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

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

Предикаты

Напомню, что предикат — это функция-проверка, она всегда возвращает либо true , либо false .

В большинстве языков предикаты предваряют префиксом is .

isEmpty(); isValid(); isBusy(); 

Но не все языки следуют этому правилу. В большинстве лиспов, а так же в ruby (который взял это из лиспов) используется знак ? в конце слова:

empty? valid? busy? 

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

Вхождение

Не все предикаты можно выразить через is . Например, как задать вопрос, если мы хотим узнать, есть ли в списке чисел нечетное? В таких ситуациях принято использовать слово has :

node.hasChildren(); 

Количество

Если вам нужна переменная, в которой содержится количество чего-либо, используйте комбинацию: сущность во множественном числе + count .

symbolsCount peopleCount 

Это правило важнее даже в другом варианте, а именно, как не надо называть переменную, обозначающую количество:

errors; 

Такое именование гарантированно вводит в заблуждение. Сущность во множественном числе всегда должна обозначать только коллекцию.

Примеры

// Нормализация данных normalizeDomainName('hexlet.io'); // Извлечение части данных getName(user); getDomainFromEmail('support@hexlet.io'); // Получение массива с ошибками const errors = validate(user); if (errors.length > 0)  // . > // Подсчеты calculateDiff(first, second) // Допуск canSwim(user) canViewProfile(user) 

Категория:Нотации

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

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

Для отражения одного или нескольких видов модели в каком-то виде документов используются нотации, поддерживающие (supports) тот язык, который использует (uses) тот или иной вид моделей. Один язык может быть использован множеством видов моделей, а вид модели использует только один язык.

Письменные нотации

Типы письменности человеческих языков:

  • Пиктографический — письменный знак привязан к определенному объекту.
  • Идеографический — письменный знак привязан к определённому смыслу.
  • Фоноидеографический — письменный знак привязан и к смыслу, и к звучанию
    • Логографический — письменный знак обозначает определённое слово
    • Морфемный — письменный знак обозначает определённую морфему (см. «Китайская письменность»)

    Нотации в программировании

    • Форма Бэкуса — Наура (сокр. БНФ, Бэкуса — Наура форма) — формальная система описания синтаксиса, в которой одни синтаксические категории последовательно определяются через другие категории. БНФ используется для описания контекстно-свободных формальных грамматик. Существует расширенная форма Бэкуса — Наура (РБНФ), отличающаяся лишь более ёмкими конструкциями.
    • Венгерская нотация — соглашение об именовании переменных, констант и прочих идентификаторов в коде программ. Суть венгерской нотации сводится к тому, что имена идентификаторов предваряются заранее оговорёнными префиксами, состоящими из одного или нескольких символов. При этом, как правило, ни само наличие префиксов, ни их написание не являются требованием языков программирования, и у каждого программиста (или коллектива программистов) они могут быть своими.
    • Математические языки разметки нотации для представления математических формул:
      • TeX/LaTeX
      • MathML

      Нотации в управлении

      • Therblig — базовые элементарные движения в управлении операциями

      Нотации в математике

      • Нотации для представления различных математических идей
        • Нотации в теории вероятностей
        • Прямоугольная система координат
        • Нотации для дифференциального исчисления
        • «O» большое — математическое обозначение для сравнения асимптотического поведения функций. Применяется, например, для определения вычислительной сложности алгоритма.
        • Z-нотация — формальный язык спецификации, используемый для описания и моделирования программ и их формальной верификации.
        • Порядковая индексация
        • Форма записи числовых множеств
        • Нотация Конвея
        • Стрелочная нотация Кнута
        • Нотация Штейнгауза — Мозера
        • по способу изображения чисел системы
          • Позиционные
          • Непозиционные
          • Смешанные
          • двоичная
          • десятичная
          • восьмеричная
          • шестнадцатеричная
          • двоично-десятичная
          • естественная форма (форма с фиксированной запятой)
          • нормальная форма (форма с плавающей запятой)
          • Инфиксная нотация
          • Польская нотация
          • Обратная польская нотация

          Нотации в физике

          • Для обозначения физических величин и понятий в физике используются буквы латинского и греческого алфавитов, а также несколько специальных символов и диакритических знаков. Поскольку количество физических величин больше количества букв в латинском и греческом алфавитах, одни и те же буквы используются для обозначения различных величин. Для некоторых физических величин принято несколько обозначений (например для энергии, скорости, длины и других), чтобы предотвратить путаницу с другими величинами в данном разделе физики.
          • Диакритические знаки добавляются к символу физической величины для обозначения определённых различий (производная, векторная величина, средне значение, оператор и др.).
          • Бра и кет (англ. bra-ket < bracket скобка) — алгебраический формализм, предназначенный для описания квантовых состояний. Называется также обозначениями Дирака. В матричной механике данная система обозначений является общепринятой.
          • Обозначение тензоров. Тензор обычно обозначают некоторой буквой с совокупностью верхних (контрвариантных) и нижних (ковариантных) индексов. При смене базиса ковариантные компоненты меняются так же, как и базис (с помощью того же преобразования), а контравариантные — обратно изменению базиса (обратным преобразованием).

          Графические нотации

          • Семейства IDEF (Integrated DEFinition):
            • IDEF0 (функциональное моделирование);
            • IDEF1.X (информационное моделирование);
            • IDEF3 (моделирование деятельности или процессное моделирование).

            Страницы в категории «Нотации»

            Показано 12 страниц из 12, находящихся в данной категории.

            Венгерская нотация

            Венге́рская нота́ция в программировании — соглашение об именовании переменных, констант и прочих идентификаторов в коде программ. Своё название венгерская нотация получила благодаря программисту компании Microsoft венгерского происхождения Чарльзу Симони (венг. Simonyi Károly ), предложившему её ещё во времена разработки первых версий MS-DOS. Эта система стала внутренним стандартом Майкрософт [1] .

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

            Применяемая система префиксов зависит от многих факторов:

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

            Примеры

            Префиксы, задающие тип

            Префикс Сокращение от Смысл Пример
            s string строка sClientName
            sz zero-terminated string строка, ограниченная нулевым символом szClientName
            n, i int целочисленная переменная nSize, iSize
            l long длинное целое lAmount
            b boolean булева переменная bIsEmpty
            a array массив aDimensions
            t, dt time, datetime время, дата и время tDelivery , dtDelivery
            p pointer указатель pBox
            lp long pointer двойной (дальний) указатель lpBox
            r reference ссылка rBoxes
            h handle дескриптор hWindow
            m_ member переменная-член m_sAddress
            g_ global глобальная переменная g_nSpeed
            C class класс CString
            T type тип TObject
            I interface интерфейс IDispatch
            v void отсутствие типа vReserved

            Как видно в приведённом примере, префикс может быть и составным. Например, для именования строковой переменной-члена класса использована комбинация префиксов «m_» и «s» ( m_sAddress ).

            Префиксы, задающие смысл

            Венгерская нотация для приложений:

            Префикс Сокращение от Смысл Пример
            i index Индекс int ix; Array[ix] = 10;
            d delta Разница между значениями int a, b; . dc = b — a;
            n number Количество size_t nFound = 0;

            За и против

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

            Преимущества

            • Если встроенного механизма типизации не хватает, венгерская нотация позволяет записывать подтип переменной — например, int cPrice может означать, что переменная имеет не просто целый тип, а валютный (currency). Именно такое применение префиксов было предложено Симони [2] . Это может пригодиться:
              • В низкоуровневом программировании (когда набор доступных типов настолько узок, что, например, целый тип не отличается от булевого).
              • В языках с динамической типизацией, например PHP, где одна и та же переменная может хранить значения любого типа.
              • В инженерных расчётах (для записи единиц измерения). Это позволяет избавиться от немалого количества ошибок простым подсчётом размерностей.
              • В других местах, где переменные одного и того же типа предназначены для хранения разнородных данных — например, в коде защиты от компьютерных взломщиков префикс может указывать на «безопасные» и «небезопасные» данные (SQL-инъекция, XSS).

              Этот стиль выбора имён называется «венгерской» записью по названию родины руководителя отдела программирования Microsoft Чарльза Симони, который его изобрёл. (А не потому, что его использование придаёт программам такой вид, будто они написаны на венгерском языке [3] )

              А. Голуб. Верёвка достаточной длины.

              Недостатки

              • Некоторые программисты считают, что использование префиксов делает имена переменных менее понятными и, таким образом, ухудшает читаемость кода. [4]
              • Если известно имя переменной без префиксов, подчас трудно восстановить её префиксы.
              • Система автодокументации, если она не понимает системы префиксов, отсортирует алфавитный список по префиксу, что может отрицательно сказаться на качестве документации. Впрочем, имена функций обычно префиксами не снабжают.
              • Запись нескольких префиксов из-за частого использования заглавных букв и знаков подчёркивания может стать «пляской на кнопке ⇧ Shift».
              • Средства навигации, которые включены в современные редакторы кода, и так позволяют видеть тип любой переменной и быстро переходить к точке, где она определена — то есть, использование префиксов может быть избыточным.
              • При изменении типа потребуется изменять имя переменной (большинство программистских редакторов не могут делать это автоматически). [4]
              • Существуют и другие средства задания типа переменной в её имени: например, слова is, has и т. д. для булевского типа ( IsLoggedIn ), count для счётчика ( RefCount ), множественное число для массива ( UserIds ). В языках, в которых заглавные буквы не эквивалентны строчным, регистр букв также может кодировать что-либо.

              Известный противник венгерской нотации — Линус Торвальдс: «Вписывание типа переменной в её имя (так называемая венгерская нотация) ущербно — компилятор и так знает типы и может проверить их, и это запутывает программиста» [5] .

              См. также

              Примечания

              1. Hungarian Notation
              2. Джоэл Спольски. Как заставить неправильный код выглядеть неправильно
              3. Венгерский язык, хоть и имеет латинский алфавит, считается крайне неудобочитаемым для неосведомлённых.
              4. 12Inside C++ — Венгерская нотация
              5. «Linux kernel coding style». Документация по ядру Linux (на английском).
              • Стандарт оформления кода

              Что такое «O» большое в программировании?

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

              Дело в том, что время выполнения написанной программы зависит от переданных входных данных.

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

              Прежде чем перейти к ответам, разберемся с тем, как вообще работает эффективная программа. И в этом поможет одна забавная история.

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

              Один метод заключался в использовании почтового голубя, к лапке которого привязали USB-флешку.

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

              Самое интересное заключалось в том, что голубь обогнал интернет. Но как?

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

              Перейдем к вычислительным сложностям

              Вот две сложности, связанные с программированием.

              • Временная: время, необходимое для обработки входных данных.
              • Пространственная: количество места, требуемое для обработки входных данных.

              Что такое нотация “О” большое?

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

              Проще говоря, термином “О” большое определяется, как время выполнения растет по мере увеличения входных данных.

              • Увеличение времени выполнения. Поскольку время, необходимое для выполнения программы, зависит от процессора компьютера, используется “О” большое, чтобы показать, как меняется время выполнения.
              • Ввод данных. Поскольку проверяется не только время, которое требуется для выполнения программы, но и ввод, в нотации “О” большое есть “n”, которое определяет количество элементов обрабатываемых входных данных. Поскольку время выполнения растет с увеличением размера входных данных, эту величину можно представить в виде O(n).
              • По мере увеличения входных данных. По мере увеличения входных данных программам иногда требуется больше времени для выполнения, что приводит к проблемам с производительностью. Поэтому разрабатываемую программу нужно проверять по мере увеличения входных данных.

              Визуализированные примеры

              O(1) не увеличивается с изменением размера входных данных. Таким образом, время обработки O(1) — величина постоянная независимо от того, какие входные данные были переданы.

              Пример:

              let names = ['Atit', 'mahesh', 'ramesh', 'kamlesh'];
              let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
              function checkLength(data) return data.length;
              >
              console.log(checkLength(names)); // 4
              console.log(checkLength(data)); // 10

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

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

              Пример:

              function print(array) for (var i = 0; i < array.length; i++) console.log(array[i]); 
              >
              >
              print(names) //4 times
              print(data) //10 times

              Показывает производительность пропорционально размеру входных данных. O(n²) представляет наихудшую производительность.

              Пример:

              function testdata(data) data.forEach(function(items) console.log('values ', data); 
              items.forEach(function(number) console.log('Marks', number); //
              >);
              >);
              >
              const test = [
              ['maths', 52],
              ['science', 65],
              ['english', 72]
              ]
              testdata(test)

              Логарифмическая | O(log n)

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

              Пример:

              function log(n) for (let i = 1; i < n; i = i * 2) const result = i; 
              console.log(result);
              >
              >
              log(4); //2

              Для данной программы с любыми итерациями значение i = i*2. Поэтому на n-й итерации значение i= i*n и i всегда меньше размера самого цикла (N).

              Следовательно, можно получить:

              2^n < N
              log(2^n) < log(N)
              n < log(N)

              Таким образом, наихудшая временная сложность такого алгоритма будет равна O(log(n)).

              Отбросим константы

              Существует вероятность того, что O(N) код быстрее, чем O(1) код для определенных входных данных. “О” большое просто описывает скорость увеличения. По этой причине мы отбрасываем константу, что означает, что O(3N) на самом деле O(N):

              Можно отбросить не только константы, но и неглавные члены:

              • O(N3+N) → O(N3)
              • O(N+logN) → O(N)
              • O(2∗2N + 1000N100) → O(2N)

              Как вычислить сложность?

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

              Циклы (Loops)

              • Внутри цикла операторы повторяются n раз. Если для выполнения кода требуется сложность O(m), то внутри n раз повторенного цикла она будет равна n∗O(m) или O(n∗m).
              for (let i in arr1) print(i);
              >
              • Количество циклов будет равно 4, а выполнение кода внутри цикла равно O(1), поэтому суммарное выполнение будет равно O(4).

              Вложенные циклы ( Nestedloops )

              • Если один цикл находится внутри другого цикла, сложность будет расти экспоненциально. Другими словами, если сложность простого цикла равна O(n), добавление еще одного цикла внутри этого цикла сделает сложность O(n²).
              for (let i in arr1) print(i); 
              for (let j in i) <>
              >
              • Здесь сложность первого цикла равна O(5), поскольку количество массивов равно 5, поэтому вложенный цикл также выполняется с той же сложностью 5 раз, а значит, оба цикла будут O(5²).
              • Важные аспекты математики в науке о данных — «что» и «почему»
              • Решение алгоритмических проблем: Поиск повторяющихся элементов в массиве
              • 8 показателей эффективности классификации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *