Греппабельность — важная метрика кода

от автора

A surveyor searching for metal in a field

При работе над поддержкой незнакомой мне кодовой базы я трачу кучу времени на поиск строк при помощи grep. Даже в проектах, полностью написанных мной, мне нужно много искать: имена функций, сообщения об ошибках, имена классов и тому подобное. Если я не могу найти нужное, то я буду как минимум расстроен, а как максимум могу создать опасную ситуацию, если предположу, что какой-то элемент больше не нужен, ведь я не могу найти ссылок на него в кодовой базе. На основании этих ситуаций я выработал правила, которые позволяют повысить греппабельность кода.

Не разделяйте идентификаторы

Оказалось, что разбиение или динамическое создание идентификаторов — это плохая идея.

Допустим, у нас есть две таблицы базы данных shipping_addressesbilling_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/