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

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

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

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

Чтение

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 *EnergyДоменные величины

Безразмерные величины, которым суффикс не нужен: x y z id 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

userData → user. trackInfo → track или trackSummary. parseResult → parsedTrack. Если после удаления пустого слова имя стало неотличимо от другого в той же области видимости — значит эти две сущности и правда одно и то же, либо одной из них нужно настоящее имя.

Сокращения

Разрешены ровно эти: 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