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

Правила именования

Цель: Создать предсказуемую и читаемую кодовую базу, где имена говорят сами за себя.

См. также: Сегменты - где размещать различные типы файлов.


Именование файлов и директорий

MUST

  • Директории и файлы именуются в lower-kebab-case.
✅ CORRECT
user-profile/
use-get-user-data.ts
avatar-upload.tsx
article-list.module.css
format-date.ts

❌ FORBIDDEN
UserProfile/
useGetUserData.ts
AvatarUpload.tsx
articleList.module.css
formatDate.ts
  • Компоненты именуются в UpperCamelCase (PascalCase).
// ✅ CORRECT
export function UserProfile() {}
export function ProgressIndicator() {}
export function ArticleCard() {}

// ❌ FORBIDDEN
export function userProfile() {}
export function progress_indicator() {}
export function articlecard() {}
  • Файл index.ts используется только как Public API модуля.
// ✅ CORRECT
// entities/article/index.ts - Public API
export { ArticleCard } from './ui/article-card';
export { useArticle } from './model/use-article';

// ❌ FORBIDDEN
// entities/article/ui/index.tsx - анонимный компонент
export default function Article() {}

FORBIDDEN

  • Использовать анонимные названия файлов (кроме index.ts для Public API).
❌ FORBIDDEN
styles.ts
index.module.scss
index.tsx
component.tsx

✅ CORRECT
article-card.module.scss
use-article.ts
article-card.tsx
index.ts (только для Public API)

A/HC/LC Pattern для функций и переменных

Визуальная схема паттерна

Структура паттерна

[Prefix]? + Action + HighContext + [LowContext]?
ЭлементОбязательностьПримерыКогда применять
Prefix (P)Опциональноis, has, should, canДля boolean переменных
Action (A)Обязательноget, set, fetch, handleВсегда для функций
High Context (HC)ОбязательноUser, Article, OrderОсновная сущность
Low Context (LC)ОпциональноList, Count, ErrorУточнение при необходимости

Префиксы (Prefix)

MUST

  • Использовать префиксы для boolean переменных и функций-предикатов.
ПрефиксЗначениеКогда использоватьПримеры
isСостояние или характеристикаТекущее состояние, свойствоisAuthorized, isPending, isValid
hasНаличие чего-либоПроверка наличия данныхhasAccess, hasError, hasChildren
shouldУсловие для действияЛогическое условиеshouldShowActions, shouldRedirect
canВозможность действияПроверка разрешенийcanDeletePost, canEditArticle

Примеры:

// ✅ CORRECT - is для состояния
const isAuthorized = Boolean(token);
const [isPending, setIsPending] = useState(false);
const isValidEmail = email.includes('@');
const isArticlePublished = article.status === 'published';

// ✅ CORRECT - has для наличия
const hasAccess = permissions.includes('admin');
const hasUnreadMessages = messages.some((m) => !m.read);
const hasRequiredFields = Boolean(title && content);

// ✅ CORRECT - should для условий
const shouldShowActions = isAuthorized && hasAccess;
const shouldRedirect = !user && !isLoading;
const shouldDisableSubmit = !isValid || isPending;

// ✅ CORRECT - can для возможностей
const canDeletePost = user.id === post.authorId || user.role === 'admin';
const canEditArticle = isOwner && !article.published;
const canAccessAdminPanel = user.role === 'admin';

FORBIDDEN

  • Использовать неправильные префиксы или их отсутствие для boolean.
// ❌ FORBIDDEN - отсутствие префикса
const authorized = Boolean(token); // Используйте isAuthorized
const valid = checkEmail(email); // Используйте isValid
const loading = true; // Используйте isLoading

// ❌ FORBIDDEN - неправильный префикс
const checkAuthorized = Boolean(token); // Используйте isAuthorized
const getIsValid = () => true; // Используйте isValid

Действия (Actions)

MUST

  • Глагольная часть имени должна описывать, что делает функция.
ActionЗначениеКогда использоватьПримеры
getПолучение/доступ к даннымСинхронное получение из памяти/стораgetUser, getDraftFromStore
setОбновление значенияИзменение состояния/переменнойsetTitle, setUserRole
fetchПолучение данных извнеАсинхронный запрос к API/БДfetchUserProfile, fetchArticles
handleОбработка события/ошибкиEvent handlers, обработчики ошибокhandleClick, handleSubmit
createСоздание новой сущностиСоздание объекта/записиcreateArticle, createUser
updateОбновление существующей сущностиИзменение существующих данныхupdateArticle, updateProfile
deleteУдалениеУдаление данныхdeleteComment, deleteUser
validateПроверка валидностиВалидация данныхvalidateEmail, validateForm
formatФорматированиеПреобразование для отображенияformatDate, formatCurrency

Примеры:

// ✅ CORRECT - get (синхронное получение)
const getUser = (id: string) => users.find((u) => u.id === id);
const getUserName = (user: User) => user.name;
const getDraftFromStore = () => store.getState().draft;

// ✅ CORRECT - set (обновление состояния)
const setTitle = (title: string) => setState({ title });
const setUserRole = (role: Role) => (user.role = role);
const setIsLoading = (loading: boolean) => setState({ isLoading: loading });

// ✅ CORRECT - fetch (асинхронный запрос)
const fetchUserProfile = async (id: string) => await api.get(`/users/${id}`);
const fetchArticles = async () => await api.get('/articles');
const fetchCommentsByArticle = async (slug: string) =>
await api.get(`/articles/${slug}/comments`);

// ✅ CORRECT - handle (обработчики)
const handleSubmit = (e: FormEvent) => {
/* ... */
};
const handleClick = () => {
/* ... */
};
const handleUserNotFound = (error: Error) => {
/* ... */
};

// ✅ CORRECT - create/update/delete
const createArticle = async (data: ArticleData) =>
await api.post('/articles', data);
const updateArticle = async (id: string, data: Partial<Article>) =>
await api.patch(`/articles/${id}`, data);
const deleteComment = async (id: string) => await api.delete(`/comments/${id}`);

// ✅ CORRECT - validate/format
const validateEmail = (email: string) =>
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const formatArticleDate = (date: string) => new Date(date).toLocaleDateString();
const formatCurrency = (amount: number) =>
new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
amount
);

FORBIDDEN

  • Использовать синонимы вместо стандартных действий.
// ❌ FORBIDDEN - неправильные действия
const retrieveUser = () => {}; // Используйте getUser или fetchUser
const loadProfile = async () => {}; // Используйте fetchUserProfile
const modifyArticle = () => {}; // Используйте updateArticle
const removeComment = () => {}; // Используйте deleteComment
const checkEmail = () => {}; // Используйте validateEmail

// ❌ FORBIDDEN - слишком общие действия
const processData = () => {}; // Что именно делается?
const doSomething = () => {}; // Неинформативно
const execute = () => {}; // Что выполняется?

Контекст (High Context + Low Context)

MUST

  • High Context (HC) всегда присутствует и отражает основную бизнес-сущность.
// ✅ CORRECT - HC присутствует
const getUser = (id: string) => users.find((u) => u.id === id);
const fetchArticle = async (slug: string) => api.get(`/articles/${slug}`);
const handleCommentSubmit = (data: CommentData) => {
/* ... */
};
const isOrderCompleted = order.status === 'completed';
  • Low Context (LC) добавляется только при необходимости уточнения.
// ✅ CORRECT - LC добавлен для уточнения
const getUserList = () => users; // Список
const getArticleCount = () => articles.length; // Количество
const fetchUserProfile = (id: string) => api.get(`/users/${id}/profile`); // Профиль
const handleArticleError = (error: Error) => {
/* ... */
}; // Обработка ошибки

// ✅ CORRECT - без LC, когда уточнение не требуется
const getUser = (id: string) => users.find((u) => u.id === id);
const fetchArticle = async (slug: string) => api.get(`/articles/${slug}`);

Структура HC + LC

Action + HighContext + [LowContext]?

Примеры:

// ✅ Action + HC (простой случай)
const getUser = (id: string) => users.find((u) => u.id === id);
const fetchArticle = async (slug: string) => api.get(`/articles/${slug}`);
const createComment = async (data: CommentData) => api.post('/comments', data);

// ✅ Action + HC + LC (с уточнением)
const getUserList = () => users; // Список
const getUserCount = () => users.length; // Количество
const fetchUserProfile = (id: string) => api.get(`/users/${id}/profile`); // Профиль
const getArticleDraft = (id: string) => drafts.find((d) => d.id === id); // Черновик
const handleArticleError = (error: Error) => {
/* ... */
}; // Обработка ошибки

// ✅ Prefix + Action + HC + LC
const isUserListEmpty = users.length === 0;
const hasUnreadMessages = messages.some((m) => !m.read);
const shouldShowErrorMessage = hasError && !isLoading;
const canDeleteArticleDraft = isOwner || isAdmin;

FORBIDDEN

  • Слишком общие имена без контекста.
// ❌ FORBIDDEN - нет контекста
const getData = () => {}; // Какие данные?
const fetchInfo = () => {}; // Какая информация?
const getList = () => {}; // Список чего?
const handleError = () => {}; // Какой ошибки?
const isValid = true; // Что валидно?

// ✅ CORRECT - с контекстом
const getUserData = () => {};
const fetchArticleInfo = () => {};
const getCommentList = () => {};
const handleArticleError = () => {};
const isEmailValid = true;
  • Избыточное уточнение в LC.
// ❌ FORBIDDEN - избыточное уточнение
const getUserListArrayData = () => {}; // Слишком длинно
const fetchArticleObjectFromAPI = () => {}; // Избыточно
const getOrderItemsListArray = () => {}; // Дублирование
const handleFormSubmitEvent = () => {}; // Лишнее "Event"

// ✅ CORRECT - лаконично
const getUserList = () => {};
const fetchArticle = () => {};
const getOrderItems = () => {};
const handleFormSubmit = () => {};

Практические примеры с разбором

Пример 1: Получение данных

// ✅ CORRECT - простое получение
const getUser = (id: string) => users.find((u) => u.id === id);
// Структура: get (A) + User (HC)

// ✅ CORRECT - с уточнением
const getUserById = (id: string) => users.find((u) => u.id === id);
// Структура: get (A) + User (HC) + ById (LC)

// ✅ CORRECT - список
const getUserList = () => users;
// Структура: get (A) + User (HC) + List (LC)

Пример 2: Проверка состояния

// ✅ CORRECT - простая проверка
const isPublished = article.status === 'published';
// Структура: is (P) + Published (HC)

// ✅ CORRECT - с контекстом
const isArticlePublished = article.status === 'published';
// Структура: is (P) + Article (HC) + Published (LC)

// ✅ CORRECT - проверка возможности
const canEditArticle = isOwner && !isArticlePublished;
// Структура: can (P) + Edit (A) + Article (HC)

Пример 3: Обработчики событий

// ✅ CORRECT - простой обработчик
const handleClick = () => {
/* ... */
};
// Структура: handle (A) + Click (HC)

// ✅ CORRECT - с контекстом действия
const handleSubmit = (e: FormEvent) => {
/* ... */
};
// Структура: handle (A) + Submit (HC)

// ✅ CORRECT - с полным контекстом
const handleArticleSubmit = (data: ArticleData) => {
/* ... */
};
// Структура: handle (A) + Article (HC) + Submit (LC)

// ✅ CORRECT - обработка конкретной формы
const handleArticleFormSubmit = (e: FormEvent) => {
/* ... */
};
// Структура: handle (A) + ArticleForm (HC) + Submit (LC)

Пример 4: Сложные случаи

// ✅ CORRECT - вложенная структура
const getUserProfileSettings = (userId: string) => {
/* ... */
};
// Структура: get (A) + UserProfile (HC) + Settings (LC)

// ✅ CORRECT - множественные проверки
const shouldShowArticleEditButton = isAuthorized && canEditArticle;
// Структура: should (P) + Show (A) + ArticleEditButton (HC+LC)

// ✅ CORRECT - асинхронное получение с уточнением
const fetchUserDraftArticles = async (userId: string) => {
/* ... */
};
// Структура: fetch (A) + User (HC) + DraftArticles (LC)

// ✅ CORRECT - специфичная валидация
const validateCorporateEmail = (email: string) => {
/* ... */
};
// Структура: validate (A) + Corporate (LC) + Email (HC)
// Или: validate (A) + CorporateEmail (HC)

Контрольный список для проверки имени

Для функций

  • Начинается с глагола (action): get, set, fetch, handle, и т.д.
  • Содержит High Context (сущность): User, Article, Order
  • Low Context добавлен только при необходимости уточнения
  • Имя читается как предложение: getUserProfile() = "get user profile"
  • Длина ≤ 4 слов (prefix + action + HC + LC)
  • Нет синонимов стандартных действий (retrieveget, modifyupdate)

Для переменных

  • Boolean переменные начинаются с is, has, should, can
  • Имя отражает содержимое: userList, а не data
  • Используется camelCase
  • Избегайте сокращений (кроме общепринятых: id, url, api)
  • Нет магических чисел — используйте именованные константы

Для констант

  • UPPER_SNAKE_CASE для глобальных констант: MAX_RETRY_COUNT
  • camelCase для локальных констант: defaultPageSize
  • Имя отражает назначение, а не значение

Таблица правильных и неправильных имен

❌ FORBIDDEN✅ CORRECTПочему
authorizedisUserAuthorizedBoolean без префикса
unreadMessageshasUnreadMessagesBoolean без префикса
showModalshouldShowModalУсловие без префикса
deleteAllowedcanDeletePostВозможность без префикса
user()getUser()Функция без глагола
retrieveUsers()getUserList()Синоним вместо get
loadProfile()fetchUserProfile()Синоним вместо fetch
onSubmit()handleSubmit()React-событие должно быть handle
add()createArticle()Слишком общее действие
modify()updateArticle()Синоним вместо update
remove()deleteComment()Синоним вместо delete
dateFormat()formatArticleDate()Глагол после существительного
emailCheck()validateEmail()Неправильное действие
getData()getUserData()Нет контекста
fetchInfo()fetchArticleInfo()Нет контекста

Специальные случаи

SHOULD

  • Для React-хуков использовать префикс use.
// ✅ CORRECT
const useUser = (id: string) => {
return useQuery({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
});
};

const useArticleList = (filters: ArticleFilters) => {
return useQuery({
queryKey: ['articles', filters],
queryFn: () => fetchArticles(filters),
});
};
  • Для обработчиков событий в компонентах использовать handle.
// ✅ CORRECT
const handleClick = () => {
/* ... */
};
const handleSubmit = (e: FormEvent) => {
/* ... */
};
const handleArticleDelete = (slug: string) => {
/* ... */
};

// ❌ AVOID - React-стиль событий (только для props)
const onClick = () => {}; // Используйте handleClick
const onSubmit = (e: FormEvent) => {}; // Используйте handleSubmit

MAY

  • Для коротких утилит допустимы краткие имена, если контекст очевиден.
// MAY - в контексте утилит
// shared/lib/utils/string.ts
export const capitalize = (str: string) =>
str.charAt(0).toUpperCase() + str.slice(1);
export const truncate = (str: string, length: number) =>
str.slice(0, length) + '...';

// MAY - в контексте math
// shared/lib/utils/math.ts
export const clamp = (value: number, min: number, max: number) =>
Math.min(Math.max(value, min), max);
export const round = (value: number, decimals = 2) =>
Math.round(value * 10 ** decimals) / 10 ** decimals;

Резюме

  1. Файлы и директории: lower-kebab-case
  2. Компоненты: UpperCamelCase (PascalCase)
  3. Boolean: Префиксы is, has, should, can
  4. Функции: action + HighContext + [LowContext]?
  5. Стандартные действия: get, set, fetch, handle, create, update, delete
  6. Длина имени: ≤ 4 слов (prefix + action + HC + LC)
  7. Контекст обязателен: Избегайте общих имён без контекста