При работе над поддержкой незнакомой мне кодовой базы я трачу кучу времени на поиск строк при помощи grep. Даже в проектах, полностью написанных мной, мне нужно много искать: имена функций, сообщения об ошибках, имена классов и тому подобное. Если я не могу найти нужное, то я буду как минимум расстроен, а как максимум могу создать опасную ситуацию, если предположу, что какой-то элемент больше не нужен, ведь я не могу найти ссылок на него в кодовой базе. На основании этих ситуаций я выработал правила, которые позволяют повысить греппабельность кода.
Не разделяйте идентификаторы
Оказалось, что разбиение или динамическое создание идентификаторов — это плохая идея.
Допустим, у нас есть две таблицы базы данных shipping_addresses
, billing_addresses
,. Может показаться абсолютно нормальным решением создавать имя таблицы динамически по порядковому типу.
const getTableName = (addressType: 'shipping' | 'billing') => { return `${addressType}_addresses` }
Хотя кажется, что это красиво и соответствует DRY, для поддержки это не очень удобно: кто-то неизбежно будет искать в кодовой базе имя shipping_addresses
и пропустит это вхождение.
Отрефакторим код для повышения греппабельности:
const getTableName = (addressType: 'shipping' | 'billing') => { if (addressType === 'shipping') { return 'shipping_addresses' } if (addressType === 'billing') { return 'billing_addresses' } throw new TypeError('addressType must be billing or shipping') }
То же самое относится к именам столбцов, полям объектов и, упаси боже, именам методов/функций (в Javascript можно создавать имена классов динамически).
Используйте одни и те же имена для элементов во всём стеке
Не переименовывайте поля на границах приложений, чтобы соответствовать схемам наименований. Очевидный пример: мы импортируем идентификаторы в snake_case в стиле Postgres в код на Javascript, а затем преобразуем их в camelCase. Это усложняет поиск — теперь чтобы найти все вхождения, вам нужно использовать grep для двух строк вместо одной!
const getAddress = async (id: string) => { const address = await getAddressById(id) return { streetName: address.street_name, zipCode: address.zip_code, } }
Лучше пойти более сложным путём и возвращать непосредственно объект:
const getAddress = async (id: string) => { return await getAddressById(id) }
Плоская структура лучше вложенной
Я взял этот совет из Дзена Пайтона: при работе с пространствами имён уплощение структур папок/объектов обычно лучше, чем вложенность.
Например, если у вас есть два варианта настройки файлов перевода:
{ "auth": { "login": { "title": "Login", "emailLabel": "Email", "passwordLabel": "Password", }, "register": "title": "Register", "emailLabel": "Email", "passwordLabel": "Password", } } }
и
{ "auth.login.title": "Login", "auth.login.emailLabel": "Email", "auth.login.passwordLabel": "Password", "auth.register.title": "Login", "auth.register.emailLabel": "Email", "auth.register.passwordLabel": "Password", }
то выберите второй! Тогда вы с лёгкостью можете находить ключи, ссылки на которые предположительно будут выглядеть так: t('auth.login.title')
.
Или рассмотрим структуру компонентов React. Структура компонентов
./components/AttributeFilterCombobox.tsx ./components/AttributeFilterDialog.tsx ./components/AttributeFilterRating.tsx ./components/AttributeFilterSelect.tsx
предпочтительнее, чем
./components/attribute/filter/Combobox.tsx ./components/attribute/filter/Dialog.tsx ./components/attribute/filter/Rating.tsx ./components/attribute/filter/Select.tsx
с точки зрения греппабельности, потому что вы сможете выполнять поиск grep всего компонента AttributeFilterCombobox
в пространстве имён просто по его использованию, а не по строке Dialog
, которая может встречаться в приложении во многих местах.
ссылка на оригинал статьи https://habr.com/ru/articles/840654/
Добавить комментарий