Глаголы и имена

Last updated: 2026-08-18Закрытый словарь из 33 глаголов с контрактами, обязательные единицы измерения, префиксы булевых и слова, которые ничего не сообщают.

Глаголы и имена

Функция — это действие, значит имя начинается с глагола. Глагол берётся из закрытого словаря, и каждый глагол несёт контракт, который нельзя нарушать.

Чтение

find*Может вернуть null. Никогда не бросает — отсутствие это нормальный исход
get*Гарантирует значение. Нет значения — бросает. Никаких null в типе
list*Всегда коллекция. Пустая коллекция — не ошибка и не null
count*Число. Никогда не null

Одна эта пара меняет чтение кода:

ts
const track = await findTrack(trackId)
if (track === null) return makeFail('music.track.missing', 'Трек не найден')

const owner = getOwner(track)

Видно, не открывая функций: у первой отсутствие результата — штатная ситуация, у второй — баг. getOwner в этом месте означает «владелец обязан существовать, иначе данные сломаны».

Границы и хранилище

read* / write*Пересечение границы I/O: сеть, диск, объектное хранилище
load* / save*Агрегат целиком через хранилище (БД)

Разделение read и load не педантизм: по имени видно, переживёт ли вызов офлайн и стоит ли его кэшировать.

Вычисление

make*Чистый конструктор значения. Без I/O, без времени, без случайности
derive*Чистое вычисление из уже имеющихся данных
resolve*Выбор одного варианта из нескольких по правилам
parse* format*Разбор и представление: вход → выход, без состояния
encode* decode*Смена представления без потери смысла
normalize*Приведение к канонической форме
sign* verify* hash*Криптографические преобразования

Изменение

create* / delete*Мутация домена: меняет состояние и порождает событие
archive* / restore*Обратимое изъятие из оборота
ensure*Идемпотентно приводит состояние к нужному — повторный вызов ничего не меняет
assert*Бросает при нарушении инварианта, иначе void. Ничего не возвращает
apply*Накатывает готовое изменение на цель
set*Присваивает значение, дальше по системе ничего не происходит

Связь и жизненный цикл

emit*В шину. Адресат неизвестен и не важен
send*Конкретному адресату — адресат часть имени: sendVerifyEmail
start* / stop*Жизненный цикл процесса или подсистемы
use* with* render*Только в UI-коде: хуки, обёртки, отрисовка

Запрещённые глаголы

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

ЗапрещеноВместо
handle*Назови действие: submitLogin, retryPayout, dropStaleSession
process*derive* / apply* / точный глагол преобразования
manage*Функция делает больше одной вещи — раздели
do* perform* execute* run*Назови действие
check*is* если возвращает ответ, assert* если бросает
init*start* для процесса, make* для значения
update*save* / apply* / set* — что именно происходит
fetch* retrieve*read* (I/O) / load* (агрегат) / get*
calculate* compute*derive*
generate* build* prepare*make*
setup*ensure* / start*
validate*assert* (бросает) / parse* (возвращает разбор)
transform* convert*derive* / format* / encode*
determine*resolve*
trigger*emit* / send*

Порядок слов: домен → уточнение → единица

Как обычно
urlOfCover
refreshTimeout
amount
По GRAIN
trackCoverUrl
sessionRefreshTtlSec
payoutAmountCents

Общее слева, частное справа. Такие имена сортируются в осмысленные группы, а автодополнение по первому слову выдаёт всё про домен сразу.

Число без единицы измерения — ошибка

Это единственное правило GRAIN, которое ловит целый класс продакшн-багов: секунды, отданные туда, где ждали миллисекунды.

СуффиксСмысл
*AtМомент времени, всегда UTC
*Ms *Sec *Min *Hours *DaysДлительность
*Bytes *Kb *Mb *GbРазмер
*CentsДеньги, всегда в минорных единицах, всегда целое
*RatioДоля 0..1
*PctПроценты 0..100
*Count *IndexСчёт и позиция
*Px *Deg *Hz *Bpm *DbДоменные величины

Безразмерные величины, которым суффикс не нужен: x y z width height depth port page limit offset version priority. Список закрыт — если твоя величина не в нём, у неё есть единица.

Булевы — семь префиксов, других нет

is · has · can · should · was · will · must

ts
const isPublished = track.publishedAt !== null
const hasActiveSubscription = subscription.state === 'active'
const canPublish = isOwner || isAdmin

enabled, published, flag, status булевым именем не являются.

Слова, которые ничего не сообщают

Запрещены как последнее слово имени и как имя целиком:

data info obj object temp tmp stuff misc thing things
res ret arr str num flag val result
helper handler manager wrapper util utils

userDatauser. trackInfotrack или trackSummary. parseResultparsedTrack. Если после удаления пустого слова имя стало неотличимо от другого в той же области видимости — значит эти две сущности и правда одно и то же, либо одной из них нужно настоящее имя.

Сокращения

Разрешены ровно эти: id url uri db io rpc ttl utc api sql css html json jwt s3 ip dns cdn ui ms.

Всё остальное пишется целиком: config не cfg, request не req, message не msg, error не err, index не idx, previous не prev.

Длина имени пропорциональна области видимости. В колбэке на две строки t допустимо и честно. В экспортируемом API однобуквенных имён нет.

Самопохвала

enhanced advanced comprehensive ultimate robust powerful seamless smart intelligent optimized improved modern simple easy quick — в именах запрещены. Это оценка, а не описание; она устаревает в момент коммита и почти всегда означает «я не нашёл, чем эта версия отличается от прошлой».

Глаголы и имена | AS Docs