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

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

Независимо от того, каким фреймворком вы пользуетесь, и пользуетесь ли вообще, у нас есть HTML-шаблон и JavaScript-код. Код частично залезает в шаблон, и тут и появляется наша проблема. От чего отталкиваться при названии функций?

Есть два варианта. Первый – от шаблона к коду:

<button onclick="addItem()">Click</button>
function addItem() { // ... }

Мы называем функции по тому, что они делают. Я открываю файл, вижу кнопку, смотрю на её действие и сразу понимаю, что она делает. Удобно. С одной стороны. С другой стороны, если мы сначала читаем код, мы видим какую-то функцию addItem. И мы не знаем, где она используется. Чтобы узнать это, надо открыть HTML и найти её там.

Второй вариант – от кода к шаблону:

function handleButtonClick() { // ... }
<button onclick="handleButtonClick()">Click</button>

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

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

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

Во Vue.js наоборот. Сначала шаблон, потом код. Имхо, в таком случае, лучше выбрать первый вариант.

Но, главная проблема – это то, что я сейчас работаю исключительно с Angular​. И там шаблон и код в 99% случаев находятся в разных файлах. Что в таком случае выбирать? Я не знаю. Если бы знал наверняка, не писал бы сейчас эту статью.

Жду советов.

Комментарии (35)


  1. GRascm
    03.08.2021 11:34
    +2

    А почему в исходном вопросе проводится чёткая граница между HTML и JS кодом?

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

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

    Если функция делает вполне понятное, конкретное, действие, которое может быть использовано из любых контекстов (вроде createStoreItem, или addItemReview), то и называться она должна соответственно.

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

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


    1. evgeniyPP Автор
      03.08.2021 11:44

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


    1. evgeniyPP Автор
      03.08.2021 11:46

      Я также категорически против "неконсистентности" в названиях. Либо А, либо Б, никакого баланса.


    1. evgeniyPP Автор
      03.08.2021 11:53

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

      1. Называть все функции, которые встречаются в шаблоне через handle*

      2. Внутри функции handle* не делать ничего, кроме как вызывать приватные функции.

      То есть:

      <button onclick="handleButtonClick()">Click</button>
      function handleButtonClick() {
      	addItem();
      }
      
      function addItem() { // ... }


      1. evgeniyPP Автор
        03.08.2021 11:58

        Это верно, только если вы за второй вариант, потому что чтение HTML это не упрощает.


  1. flancer
    03.08.2021 11:49
    -1

    Делайте, как удобно лично вам. Какой бы вариант вы ни выбрали, кто-нибудь да укажет вам на недостатки вашего выбора.


    1. evgeniyPP Автор
      03.08.2021 12:00

      Я не переживаю за критику, я ищу истину!) Может, она есть, может, нет, но попытаться стоит.


      1. flancer
        03.08.2021 12:18

        Истина субъективна. В лучшем случае, вы можете разделить её с единомышленниками. Иногда есть идеи, которые разделяются почти всеми. Есть ли идеи, на которые всё человечество смотрит одинаково - я даже не уверен.


        1. evgeniyPP Автор
          03.08.2021 13:22

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


  1. mSnus
    03.08.2021 11:52
    +1

    Если функция обрабатывает событие нажатия такой-то кнопки btn1 то она должна называться btn1Click.

    Если функция добавляет какой-то пункт в какой-то список, она должна называться addItemToList1.

    Таким образом, обработчик клика не делает ничего (пока что), кроме вызова добавления в список addItemToList1:

    function btn1Click(){

    addItemToList1();

    }

    Это позволит избежать всякой каши в дальнейшем, например, если добавление в список происходит не только по нажатию кнопки или если нажатие кнопки не только добавляет в список1.


    1. evgeniyPP Автор
      03.08.2021 12:03

      Я параллельно с вами предложил этот вариант выше) Но, по сути, это тот же второй вариант "от кода к шаблону". Это внутренняя реализация второго варианта, она не имеет отношения к поставленной проблеме. HTML всё также нечитабелен.


      1. mSnus
        03.08.2021 12:24

        Да, увидел выше ваш комментарий, сначала принял за свой))

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


        1. evgeniyPP Автор
          03.08.2021 13:25

          Ну это крайность, конечно. `addItemToList` достаточно подробно.

          В стиле old school, не "засорять" HTML логикой – это, конечно, тоже аргумент в пользу второго варианта. Но вот пока первый выигрывает у сообщества)


          1. mSnus
            03.08.2021 14:12

            Понимаете, если мы называем функцию addItemToList, а она делает что-то кроме этого, то очень легко нарваться на то, что придётся постоянно лезть в код и смотреть, что там на самом деле происходит.

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

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


            1. evgeniyPP Автор
              03.08.2021 17:26

              `addItemToList` – это абстрактное понятие, которое включает в себя загрузку, оповещения, отправку на сервер, обновление данных и т.п.


              1. mSnus
                04.08.2021 01:15

                Тогда из названия функции не слишком понятно, что она делает, и смысл немного теряется


  1. vlreshet
    03.08.2021 11:54

    А почему просто addItem, а не более подробно? У нас же не абстрактные item-ы, мы манипулируем какими-то сущностями. Например, если это кнопка в Todo-приложении — можно ведь назвать addTaskItem. Теперь и в коде более-менее понятно что конкретно сделает эта кнопка (и где скорее всего её искать), и в шаблоне. А то ведь с таким неймингом можно вообще назвать её add, и потом жаловаться что нигде ничего не понятно :)


    1. evgeniyPP Автор
      03.08.2021 12:06

      Тут это просто как общий пример. Подразумевается, что вы максимально точно указали, что делает эта кнопка.

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


  1. Chamie
    03.08.2021 12:25
    +1

    Если по клику делается AddItem, то и кнопка, очевидно — это AddItemButton?

    <button onclick="handleAddItemButtonClick()">Add Item</button>
    Вот уже и в коде, и в шаблоне всё понятно?


  1. nin-jin
    03.08.2021 12:28
    +2

    <button id="add-item" onclick="onAddItemClick()">Add Item</button>


    1. teology
      03.08.2021 13:02

      Поддержу вариант @nin-jin

      Этот вариант предполагает ни "от шаблона к коду" и ни "от кода к шаблону". Необходимо идти "от смысла к шаблону и коду". Вы назвали кнопку "Click" - это абсолютно бессмысленный текст на кнопке, юзеру такая кнопка непонятна. Add Item - это более понятная надпись на кнопке (вроде бы).


      1. evgeniyPP Автор
        03.08.2021 13:37

        Название кнопки – не самый надежный источник информации. Там написано, что хочет видеть заказчик, что не всегда совпадает на 100% с логикой)

        Другой вопрос называть функции а-ля `onAddItemClick`. Может, в этом что-то есть


        1. teology
          04.08.2021 18:03

          Следуйте концепции DDD (domain-driven development) во всем: разработка должна двигаться предметной областью, то есть смыслом, ради чего создается ПО. То есть именование переменных, функций и прочих объектов, а также надписи на кнопках - все должно быть со смыслом. Если заказчик против, то хотя бы пометьте это в комментарии к коду ("хотел назвать кнопку Add Item, но клиент засранец"). Следование заветам DDD сделает ваш код (и надписи на кнопках) понятным ВСЕМ.

          Когда вы пишете "Click" на кнопке, как это должен понимать пользователь? Что делает эта кнопка? Все кнопки кликаются. Мы все решили, что "добавляет пункт". И вам подсказываем то, как нам диктует концепция DDD. А то вы начали тут нам задвигать о двоякости смыслов и многогранности философии. Это все ложь.

          Надо сказать, что Item - это тоже слишком абстрактно. Если кнопка добавляет новый товар в корзину, то вместо AddItem надо писать AddProduct. Короче, DDD в помощь.


  1. XXLink
    03.08.2021 13:26

    /* документируй функции */ Л - логика


    1. evgeniyPP Автор
      03.08.2021 13:38
      +1

      Л - лень)


    1. evgeniyPP Автор
      03.08.2021 13:47

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

      /**
       * Big red button on the left
      **/
      function addItem() {}


      1. XXLink
        03.08.2021 14:03

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


      1. mSnus
        03.08.2021 14:14

        Внешний вид документировать нет смысла, а вот в каком он компоненте и что делает по логике - да. По аналогии с BEM.


  1. vladaleks607
    03.08.2021 17:26

    как угодно.


  1. bgnx
    04.08.2021 01:20

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


    <div>
      ...
      <button onClick={()=> {
        project.tasks.push(new Task({text: project.newTaskText});
        project.newTaskText = "";
        ....
      }}>
          add task
      </button>
      ...
    </div>

    Тут можно сказать мол "да ты захламляешь шаблон как такое вообще читать и поддерживать когда мол верстка в перемешку с логикой?" на что я отвечу "а code folding (сворачивание) в редакторе кода для кого придумали?" Если хотите видеть/редактировать только верстку то можно легко свернуть весь код обработчиков и увидеть чистый шаблон. И наоборот — если хотите посмотреть что делает какая-то кнопка то перемещаем мышку влево на пару сантиметров и кликаем-раскрываем обработчик кнопки.


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


    И то же самое с добавлением какой-то фичи — я пишу кнопку и тут же пишу обработчик этой кнопки рядом и мне не нужно думать над тем куда вынести этот обработчик а главное — какое имя придумать этому обработчику. И также это удобно при ревью кода — когда добавляется какая-то фича то в git diff видишь изменения только в одном месте а не размазаны по кусочкам на кучу файлов/мест (верстка в одном месте, обработчик в другом месте и т.д)


    1. nin-jin
      04.08.2021 03:28

      При слиянии веток этот подход особенно удобен. Один переместил блок кода, а другой поправил в нём логику, - всё смёржится без конфликтов.


    1. ArutaGerman
      04.08.2021 17:52

      А как же переиспользование кода в таком случае?

      Ведь бывает, что 2 кнопки, с похожим функционалом, используют одни и те же куски кода и в таком случае дублировать код в каждую надо


  1. AnonimYYYs
    04.08.2021 17:52

    Так стоп. Как назвать функцию, это ведь уже работа бэка?

    Ну, тоесть, есть бэндеркэ. У него есть условный list X. И у него задача "а реализуй ка добавление нового итема в данный список". Ему плевать где и как используют эту функцию (ибо она может быть использована несколько раз в разных кнопках и иногда даже как подфункция). И вот бэкер не думает долго и пишет addNewItemToListX()

    Потом приходите уже вы. Вам дают задачу "слушай там то надо взять данные из такой формы создать на их основе итем и засунуть в лист икс. Данные я дам. Набор функций с бэка включающий в себя все необходимое я дам. Кнопку не дам". И все. Вам надо лишь найти нужную функцию в условном хедере и посмотреть ее сигнатуру. Такс, новый итем в лист хэ. Опа, addNewItemToListX(). То что надо. Все рады, все довольны.

    Ну, по крайней мере так это вижу лично я.


  1. Anonim-Nonameov
    06.08.2021 21:17

    Если функция добавляет новый элемент в список, то я бы скорее всего сделал вот так:

    <button id="button__one" onclick="addItemToList">

    Как по мне, и в коде и в шаблоне - всё понятно.


  1. 0ctav0
    06.08.2021 21:35

    Я нашел для себя удобный способ записывать так:

    const saveHandler = () => {

    if (action === "create") {

    createEvent()

    } else {

    updateEvent()

    }

    refreshEvents()

    }

    Слово save говорит о том, что это создание или редактирование и вероятно используется в кнопке сохранить.

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

    Я использую React, поэтому в моей IDE (vscode) при нажатии на идентификатор saveHandler, через ctrl, я перейду к использованию в HTML разметке.