Pull to refresh

Comments 35

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

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

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

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

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

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

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

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

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

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

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

То есть:

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

function addItem() { // ... }

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

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

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

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

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

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

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

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

function btn1Click(){

addItemToList1();

}

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

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

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

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

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

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

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

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

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

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

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

UFO just landed and posted this here

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

const saveHandler = () => {

if (action === "create") {

createEvent()

} else {

updateEvent()

}

refreshEvents()

}

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

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

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

Sign up to leave a comment.

Articles