Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 2 months, 1 week ago
С праздником, дорогие коллеги! ❤️
Именованные параметры в JavaScript
Одна из самых лучших вещей, появившихся в JavaScript за последние годы — это возможность использовать destructuring прямо в определении функции. Выглядит это так.
Обрати внимание:
• shouldKeepData = false
: можно указывать дефолтные значения для параметров.
• = {}
в конце требуется, чтобы можно было вызвать функцию без аргументов вообще: deleteUser()
. Без = {}
будет exception.
• При вызове метода можно использовать shorthand property names: см. как я передаю userId
.
Это настолько хорошо, что имеет смысл использовать практически во всех функциях и методах проекта.
Монетарные значения должны быть целочисленными
Как известно, 0.2 + 0.1 = 0.30000000000000004. Казалось бы, можно округлить да и дело с концом. Но нет: НДС от суммы в счете и сумма НДСов счета запросто могут отличаться за счет ошибок округления.
Поэтому все денежные единицы стоит хранить и исчислять в целом количестве копеек и конвертировать в дробные доллары только на этапе показа пользователю. В базах это BIGINT
. В js я делаю просто const amountHr = Math.floor(amount/100).toFixed(2)
.
С Satoshi посложнее, конечно.
Плавно вводи ресурсы в эксплуатацию
Допустим, у тебя система хранения с линейным масштабированием. Добавил новый сервер — расширилось место.
Это наивный подход к масштабированию. Если ты просто будешь добавлять в живую систему новые сервера, у тебя на них будет совершенно другой профиль нагрузки, т.к. там не будет старых лежащих данных, а будет лишь только происходить добавление новых. Этот сервер станет горячей точкой и узким горлышком.
В таких системах целесообразно сначала на новый сервер смигрировать часть старых лежащих данных и только потом вводить в эксплуатацию для добавления новых. Так ты сбалансируешь профиль нагрузки и он не будет сильно отличаться от других.
Создавай хелперы для межмодельного кода
Вот есть пользователь (User
), вот есть купоны на скидки (PromoCode
). Тебе нужно применить одно к другому.
Где разместить этот код?
В модели пользователя? Неправильно, ведь этот код дергает модель купона и он больше про скидку, чем про юзера.
В модели купона? Неправильно, ведь этот код изменяет только данные пользователя и ничьи больше.
Выход? Создай класс PromoCodeToUserApplyController
. Пусть даже там будет всего пара методов, зато точно понятно, зачем этот класс и к чему он относится. Поверь, он разрастется.
А если метод только один, то назови класс PromoCodeToUserApplyHelper
. И, кстати, хорошо в объектно-ориентированном проекте избавиться он голых функций и все вынести в классы. Да, многие тебе скажут что так делать не надо, но они имеют в виду другое. Плохой тон не в том чтобы избегать классов там, где достаточно функции; плохой тон — плодить бессмысленные классы. То есть классы, название которых не отражает их суть. Я за то, чтобы было много всяких разных изолированных сущностей и много методов, и у каждого — свое понятное название. Тогда код легко читается.
Fallback в коде: что, если не получилось?
Если в коде что-то не получилось (нет ответа от базы, API недоступен, платеж не прошел и т.д.) то важно предусмотреть правильное конструктивное поведение.
Пример из жизни (слегка упрощенный, конечно). Приложение при запуске делает запрос домой и спрашивает, оплатил ли пользователь подписку на ZZZ. Что делать приложению, если не удалось достучаться к серверам, или ответ некорректен? Скажем, прошло десять лет, компания закрылась, а домен ушел к порносайту.
Давать доступ к ZZZ.
Потому что не давать было бы деструктивным действием — у пользователя бы пропала важная для бизнеса функция и он бы страдал по нашей вине.
Exceptions нужно избегать
Exceptions полностью ломают логику твоего кода. Когда кто-то его выбрасывает, управление переходит не к следующей строчке кода, а куда-то наверх, причем порой тебе неизвестно, куда именно. Exceptions проходят мимо всего твоего стека вызовов и делают return не из текущего блока, а черт знает где и куда.
Поэтому я считаю, что есть два подхода к exceptions.
Первый: ловить как можно ближе к источнику. Оборачивай свое обращение к файлу в try { } catch
и считай, что в catch у тебя просто ветка ошибки чтения файла. Грубо говоря, это просто такой синтаксис: try { read(); } catch { }
вместо if (!read()) { }
. Это еще можно пережить. Например, в современном JavaScript они стали официальным методом получения ошибки из Promise (async/await).
Второй: лови как можно выше и умирай. Считаем, что exception, который произошел выше нижайшего уровня (первый случай) — это катастрофа. Его нужно ловить лишь для того, чтобы умереть с достоинством (сообщить об ошибке и не зависнуть).
Не надо использовать exception как инструмент для возврата ошибки! Соблазн высок: вместо протаскивания какой-то информации об ошибке всю пачку вызовов на самый верх (сложно!) — просто кинули exception и типа где-то поймали (просто). Нельзя! Через некоторое время ты перестанешь понимать ветвление собственного кода, запутаешься в ресурсах, которые нужно освбождать, ну а вся борьба с memory leaks на этом и вовсе заканчивается.
А кстати,
вместо нулевого Content-Length можно отдавать HTTP статус 204.
Совет без номера потому что.
Стоит ли автоматизировать эту задачу?
Есть простой способ узнать ответ на этот вопрос.
Сколько по времени будет стоить выполнение этой задачи вручную в течении года и сколько по времени будет стоить разработка и сопровождение и использование кода автоматизации в течении года? Выбираешь более дешевое решение.
Пример. У нас в проекте есть партнерская программа для узкого круга элитных участников. Выплаты делаются каждые два-три месяца, участников меньше десяти. Выплачивать вручную одному участнику: минута. Накладные расходы на цикл выплаты: 10 минут (кофе, открыть excel, открыть paypal, etc). 10 участников × 1 минуту × 4 раза в год + 10 накладных минут × 4 раза в год = почти 2.5 часа. На поддержку докинули 1 час на год, потому что каждая выплата сделана человеком и он в контексте.
Разработать код автоматической выплаты посчитали минимально в 12 идеальных часов: код выплаты, код учета, код показывания чека, админка для суппорта, UI для юзера, очередь запросов на выплату и т.д. Поддержку пользователей по автоматической выплате прикинули на год в 3 часа, потому что по каждой нужно будет разбираться, почему было столько.
Итого: 3.5 часа против 15 часов.
Эту задачу автоматизировать точно не стоит.
Не показывай лоадер сразу
Юзер заполняет форму, кликает submit, форма отправляется на сервер, сервер думает. На время размышлений хочется показать юзеру "форма обрабатывается". В типичном случае показываем крутящийся лоадер.
И вот так делать не надо.
В подавляющем большинстве случаев форма обрабатывается мгновенно (<1s) и лоадер будет лишь только неприятным морганием, особенно если он полноэкранный и закрывает форму. Пользователь не успеет понять, что моргнуло и почему, но у него возникнет ощущение утраты контроля — самое неприятное ощущение, какое только может создать UI.
Лоадер надо показывать спустя некоторое время после сабмита, если данные не подгрузились.
Спустя какое? Это можно узнать вот так, как на картинке.
Или просто выставить его в две секунды.
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 2 months, 1 week ago