В школе я никогда не был хорош в английском. Назовите это тем, что я не интересовался написанием правильного эссе или не интересовался Шекспиром. Урок английского был скорее возможностью вздремнуть, чем учиться. Тем не менее, одна вещь, которую я запомнил на уроках английского, не покидала меня на протяжении всей моей карьеры. Keep It Simple Stupid (или сокращенно KISS). KISS и Don’t Repeat Yourself (DRY) идут рука об руку при программировании. Если вы не повторяетесь, все становится проще. Я поделюсь несколькими вещами, которые стараюсь делать при написании кода, и помечаю их в PR-обзорах, чтобы улучшить качество кода.
Правда не ложь
В начале моей карьеры старший разработчик сказал мне:
"Не проверяйте, ложны ли данные. Это требует дополнительных размышлений по сравнению с проверкой правильности вещей».
Когда у вас есть утверждение if..else
или простая логика, вы всегда должны проверять истинность на ложность.
// Don't do const visibleItems = !showVisibleItems = [] : ['foo', 'bar']; // Instead check truthy const visibleItems = showVisibleItems = ['foo', 'bar'] : [];
Это тривиальный пример, но что происходит, когда ваша тройка является возвратом компонента React?
const TextLoader = ({ isLoading, text }) => { // Some other component logic... return !isLoading ? <span>{text}</span> : null; }
Аргумент, который я слышал в пользу этого подхода, заключается в том, чтобы сначала вернуть компонент, но я думаю, что есть лучший способ справиться с этим, чтобы сделать его более читабельным. (Что делать вместо этого, смотрите в следующем разделе)
Чтобы оставаться правдивым при именовании переменных, вы также хотите называть их положительно, а не отрицательно. Когда вы называете переменную отрицательной, проверка на ложность заставляет ваш мозг болеть от двойного отрицания.
// Stop being negative const isNonBlocker = false if (!isNonBlock) { return; } // Instead stay positive const isBlocker = true if (isBlocker) { return; }
Вернуться раньше
Поддерживая свой код в чистоте, вы хотите попытаться избежать ненужной логики и разбить код на более мелкие части. Одна вещь, которая значительно помогает в этом, — это раннее возвращение.
В компонентах React у вас будут состояния загрузки. Скорее всего, они будут проверять некоторые isLoading
переменные и отображать вращающийся или скелетный загрузчик. Возвращаясь к примеру React в первом разделе с небольшим обновлением.
// Don't return a falsey ternary const TextLoader = ({ isLoading, text }) => { // Some other component logic... return !isLoading ? <span>{text}</span> : <TextSkeleton />; } // Early return the loading state const TextLoader = ({ isLoading, text }) => { if (isLoading) { return <TextSkeleton />; } return <span>{text}</span> }
Еще один момент, о котором я должен упомянуть, это то, что, пожалуйста, не возвращайте троичный код из функции, особенно из компонента реакции. Я считаю, что это намного сложнее читать, чем раннее возвращение.
Вспомогательные функции или filter
обратные вызовы — еще одно отличное место для упрощения кода с ранним возвратом. Эти типы функций работают хорошо, потому что у вас обычно есть if..else if...else
для многократной проверки логики и возврата разных значений. Давайте посмотрим на функцию в моем приложении Remix, которая получает пользовательские данные из токена или перенаправляет на логин.
export const getUserDataOrRedirect = async (request: Request) => { const token = await getUserToken(request); if (token) { return axios.get("/user", { token }); } else { return redirect("/auth/login"); } };
Этот фрагмент выглядит не так уж плохо, относительно читаем, и вы можете понять, что происходит с первого взгляда. Пока это нормально, но что происходит, когда нам нужно добавить к этому дополнительную логику? Может быть, мы хотим проверить разрешения. Для этого нам нужно добавить вложенные операторы if, или мы можем использовать ранний возврат, чтобы избежать этого.
// Nested if statements are hard to read... export const getUserDataOrRedirect = async (request: Request) => { const token = await getUserToken(request); if (token) { const user = await axios.get("/user", { token }); if (!user) { return redirect("/auth/login"); } else { if (user.permissions !== 'owner') { return redirect("/error/permissions"); } else { return user } } } else { return redirect("/auth/login"); } }; // With early returns you can see a clear logic flow export const getUserDataOrRedirect = async (request: Request) => { const token = await getUserToken(request); if (!token) { return redirect("/auth/login"); } const user = await axios.get("/user", { token }); if (!user) { return redirect("/auth/login"); } if (user.permissions !== 'owner') { return redirect("/error/permissions"); } return user };
Что касается меня, то я трачу намного меньше времени на размышления и отслеживание того, где я нахожусь в примере с ранним возвратом, а не на вложенные обратные вызовы и if..else
поток.
Упорядочить свойства в алфавитном порядке
Хранение свойств в алфавитном порядке поможет вам быстрее находить вещи, когда у вас есть большой объект. Это особенно верно для деконструктивных реквизитов в компонентах React и объектов константного типа, используемых для поиска.
Объект ниже содержит всю информацию о дизайне моего магазина Shopify Code Bender.
export const DESIGN_DATA: Record<ProductDesigns, ProductDesignData> = { [GITHUB_C_SHARP]: { previewDesignPctWidth: 0.6, designPctWidth: 0.8, phrase: 'c#', }, [GITHUB_GO]: { previewDesignPctWidth: 0.6, designPctWidth: 0.8, phrase: 'go', }, [GITHUB_GOAT]: { phrase: 'goat', }, [GITHUB_HTML]: { phrase: 'html', }, [GITHUB_JAVA]: { phrase: 'java', }, [GITHUB_JS]: { previewDesignPctWidth: 0.6, designPctWidth: 0.8, phrase: 'js', }, [GITHUB_NERD]: { phrase: 'nerd', }, [GITHUB_PYTHON]: { phrase: 'python', }, };
Здесь у меня есть имя шаблона в свойствах в алфавитном порядке. Когда я добавляю новое свойство, вместо того, чтобы просто добавлять его в конец, добавляйте его там, где оно сохраняет свойства в алфавитном порядке. Хотя ваша IDE сообщит вам, что это ошибка дублирования ключа, ее легче найти, когда вам нужно сослаться на конкретное свойство. Это сложная вещь, чтобы всегда помнить. Я все время ошибаюсь в этом, и инструменты, которые я видел, которые автоматизируют это, работают не очень хорошо. Из-за этого я считаю это лучшим усилием. Старайтесь изо всех сил применять и рефакторить, когда что-то не так, но не держите код для исправления.
Вот несколько моментов, которым я стараюсь следовать при написании кода, и те моменты, которые я отмечаю при просмотре PR. Как и все в программировании, это лучшие практики, а не правила, а лучшие практики для поддержания чистоты и согласованности вашего кода.