Data Flow и модификация данных
Data Flow (поток данных) — концепция, описывающая движение данных между различными компонентами системы.
Желательно избегать модификации данных на всём пути этого потока, однако бывают различные ситуации, в том числе и бизнес требования, когда модифицировать данные всё же приходится. Самый простой пример — сортировка. И вот тут возникает главный вопрос — а где именно эти данные модифицировать? Универсальный (простой) ответ — максимально близко к тому месту, где это требуется.
Например, если речь идёт о какой-то локальной сортировке в одном или нескольких UI компонентах, тогда желательно это делать именно там. Грубой ошибкой, в данном случае, будет сортировка в модуле API.
И наоборот, если модификация продиктована разницей именования полей между фронтом и беком, идеальным местом будет модуль API.
Data Flow (поток данных) — концепция, описывающая движение данных между различными компонентами системы.
Желательно избегать модификации данных на всём пути этого потока, однако бывают различные ситуации, в том числе и бизнес требования, когда модифицировать данные всё же приходится. Самый простой пример — сортировка. И вот тут возникает главный вопрос — а где именно эти данные модифицировать? Универсальный (простой) ответ — максимально близко к тому месту, где это требуется.
Например, если речь идёт о какой-то локальной сортировке в одном или нескольких UI компонентах, тогда желательно это делать именно там. Грубой ошибкой, в данном случае, будет сортировка в модуле API.
И наоборот, если модификация продиктована разницей именования полей между фронтом и беком, идеальным местом будет модуль API.
🔥1
Внутренние отступы кнопок в мобильном Safari
Столкнулся с занятной особенностью мобильного Safari. Если явно не указать внутренние боковые отступы (paddings) у элемента button, браузер проставит их автоматически отталкиваясь от размера шрифта.
Кстати, если вы хотите полностью сбросить стили кнопок по умолчанию:
#development #css #safari
Столкнулся с занятной особенностью мобильного Safari. Если явно не указать внутренние боковые отступы (paddings) у элемента button, браузер проставит их автоматически отталкиваясь от размера шрифта.
Кстати, если вы хотите полностью сбросить стили кнопок по умолчанию:
button {
padding: 0;
margin: 0;
font-size: inherit;
border: none;
background: none;
appearance: none;
}
#development #css #safari
👍3🔥1
Vite vs Webpack: нюанс с React.memo()
Недавно обратил внимание на то, что Vite включает в бандл слишком много неиспользуемого кода. Чтобы выяснить, почему так происходит, я создал простой JS проект, в котором использовал последние (на момент написания) версии Vite и Webpack, с минимальной конфигурацией.
Важно: В этом примере не использовался параметр sideEffects, про него напишу отдельно.
Итак, есть некий модуль, из которого торчит два компонента:
Однако, используется только один — Test. И тут главный вопрос: что произойдёт с TestMemo при сборке проекта? Логично предположить, что раз он не используется, то и в бандл он не попадёт. Но это не совсем так!
Фрагмент сборки от Webpack:
Фрагмент сборки от Vite:
Vite, в отличие от Webpack, оставляет в бандле все компоненты которые обёрнуты в memo, forwardRef и подобные функции. И как следствие, он оставляет и всё что используется из этих компонентов. В общем, в большом проекте это может быть довольно много кода, который может тянуть внешние библиотеки и т.д. и т.п.
#development #frontend #webpack #vite
Недавно обратил внимание на то, что Vite включает в бандл слишком много неиспользуемого кода. Чтобы выяснить, почему так происходит, я создал простой JS проект, в котором использовал последние (на момент написания) версии Vite и Webpack, с минимальной конфигурацией.
Важно: В этом примере не использовался параметр sideEffects, про него напишу отдельно.
Итак, есть некий модуль, из которого торчит два компонента:
// Простой компонент
export { Test } from './test';
// Компонент обёрнутый в React.memo
export { TestMemo } from './test-memo';
Однако, используется только один — Test. И тут главный вопрос: что произойдёт с TestMemo при сборке проекта? Логично предположить, что раз он не используется, то и в бандл он не попадёт. Но это не совсем так!
Фрагмент сборки от Webpack:
function f() {
return (0, d.jsx)("p", {children: "TEST"})
}
Фрагмент сборки от Vite:
function a() {
return e.jsx("p", {children: "TEST"})
}
// Пу пу пу…
t.memo(() => e.jsx("p", {children: "MEMO"}));
Vite, в отличие от Webpack, оставляет в бандле все компоненты которые обёрнуты в memo, forwardRef и подобные функции. И как следствие, он оставляет и всё что используется из этих компонентов. В общем, в большом проекте это может быть довольно много кода, который может тянуть внешние библиотеки и т.д. и т.п.
#development #frontend #webpack #vite
🔥4
Children в SolidJS и порядок выполнения
Недавно столкнулся с не совсем очевидным моментом, связанным с props.children в SolidJS. Для понимания проблемы возьмём вот такой код:
Примечание: Опустим момент, что компонент Wrapper не реактивный, сейчас нас это не интересует.
Вопреки ожиданиям, компоненты выполнятся в следующем порядке: App > Wrapper > Content > Provider. В результате чего, контекст из Provider будет недоступен в компоненте Content. Чтобы понять, что пошло не так, давайте посмотрим во что превращается JSX при сборке проекта:
Параметр children превратился в getter функцию, которая будет выполнена при любой попытке чтения! Например, при передаче в качестве аргумента в функцию:
Очевидным решением проблемы, в данном случае, будет замена интерфейса параметра children компонента Wrapper, с JSX на функцию, вызов которой вернёт этот самый JSX:
#development #frontend #solidjs #javascript #jsx
Недавно столкнулся с не совсем очевидным моментом, связанным с props.children в SolidJS. Для понимания проблемы возьмём вот такой код:
function Wrapper(props) {
return props.when
? props.wrap(props.children, props.when)
: props.children;
}
function App() {
return (
<Wrapper
when={true}
wrap={(content) => (
<Provider>{content}</Provider>
)}
>
<Content />
</Wrapper>
);
}
Примечание: Опустим момент, что компонент Wrapper не реактивный, сейчас нас это не интересует.
Вопреки ожиданиям, компоненты выполнятся в следующем порядке: App > Wrapper > Content > Provider. В результате чего, контекст из Provider будет недоступен в компоненте Content. Чтобы понять, что пошло не так, давайте посмотрим во что превращается JSX при сборке проекта:
function App() {
return _$jsx(Wrapper, {
when: true,
wrap: content => _$jsx(Provider, {
children: content
}),
get children() {
return _$jsx(Content, {});
}
});
}
Параметр children превратился в getter функцию, которая будет выполнена при любой попытке чтения! Например, при передаче в качестве аргумента в функцию:
props.wrap(props.children, props.when)
Очевидным решением проблемы, в данном случае, будет замена интерфейса параметра children компонента Wrapper, с JSX на функцию, вызов которой вернёт этот самый JSX:
function App() {
return (
<Wrapper
when={true}
wrap={(content) => (
<Provider>{content()}</Provider>
)}
>
{() => <Content />}
</Wrapper>
);
}
#development #frontend #solidjs #javascript #jsx
🔥2
React != SolidJS на примере эффектов
Несмотря на высокую “внешнюю” схожесть, под капотом эти библиотеки отличаются как чёрное от белого. В отличие от React с его предсказуемым жизненным циклом, компоненты Solid выполняются только один раз, а дальше в дело вступает реактивная система, которая выполняет только то, что действительно должно быть выполнено, и делает это оптимально.
П.С. Менять состояние из эффектов — довольно плохая идея и лучше такого кода избегать, в React так точно.
#development #frontend #solidjs #react #javascript
Несмотря на высокую “внешнюю” схожесть, под капотом эти библиотеки отличаются как чёрное от белого. В отличие от React с его предсказуемым жизненным циклом, компоненты Solid выполняются только один раз, а дальше в дело вступает реактивная система, которая выполняет только то, что действительно должно быть выполнено, и делает это оптимально.
П.С. Менять состояние из эффектов — довольно плохая идея и лучше такого кода избегать, в React так точно.
#development #frontend #solidjs #react #javascript
🔥1
На счёт предыдущего поста. Если очень сильно хочется как в SolidJS но не хочется/можется уйти от React, то есть вот такой пакет: https://www.npmjs.com/package/@preact/signals-react
🔥1
Причина закрытия WebSocket соединения
Если вы работали с WebSocket без каких либо обёрток, возможно вы обратили внимание, что метод close может принимать два параметра: код и причину закрытия. А CloseEvent, в свою очередь, оба эти значения может содержать.
Однако, этот код не гарантирует что в логе будет 'Reason'! А всё потому, что при вызове метода close, сначала отправляется соответствующая команда на сервер, который кстати может и не ответить. Но даже если он ответил, нет гарантий что он вернёт нам эту же причину.
В общем, CloseEvent.reason — причина закрытия с сервера, поэтому там может быть всё что угодно.
П.С. Есть ещё CloseEvent.wasClean, по которому можно понять было ли соединение закрыто “чисто” или что-то пошло не так.
#development #frontend #javascript
Если вы работали с WebSocket без каких либо обёрток, возможно вы обратили внимание, что метод close может принимать два параметра: код и причину закрытия. А CloseEvent, в свою очередь, оба эти значения может содержать.
const socket = new WebSocket(url);
socket.onclose = (event) => {
console.log(event.reason);
};
socket.close(1000, 'Reason');
Однако, этот код не гарантирует что в логе будет 'Reason'! А всё потому, что при вызове метода close, сначала отправляется соответствующая команда на сервер, который кстати может и не ответить. Но даже если он ответил, нет гарантий что он вернёт нам эту же причину.
В общем, CloseEvent.reason — причина закрытия с сервера, поэтому там может быть всё что угодно.
П.С. Есть ещё CloseEvent.wasClean, по которому можно понять было ли соединение закрыто “чисто” или что-то пошло не так.
#development #frontend #javascript
👍2👎1
До кучи, вот небольшое приложение https://github.com/SanichKotikov/ws-test-app/ Писал чтобы потестировать как WebSocket будет себя вести на мобильных устройствах, в том числе в PWA. Там же есть ссылка на уже развёрнутое приложение.
GitHub
GitHub - SanichKotikov/ws-test-app
Contribute to SanichKotikov/ws-test-app development by creating an account on GitHub.
👍2
Принудительное выполнение компонента в SolidJS
Помним, что компоненты в SolidJS, в отличие от React, выполняются только “один” раз. Однако, бывают случаи когда необходимо выполнить компонент “заново” при изменении каких-то данных. Например, нужно полностью обновить форму редактирования при выборе другого блюда:
Параметр keyed компонента Show как раз для этого и предназначен. При этом, в параметре when необходимо указать значение, при изменении которого произойдёт повторное выполнение.
#development #frontend #javascript #solidjs
Помним, что компоненты в SolidJS, в отличие от React, выполняются только “один” раз. Однако, бывают случаи когда необходимо выполнить компонент “заново” при изменении каких-то данных. Например, нужно полностью обновить форму редактирования при выборе другого блюда:
<Resource data={dishData} onReload={dishActions.refetch}>
{(dish) => (
<Show keyed when={dish().id}>
<DishForm
dish={dish()}
categories={categories()}
onSubmit={onDishSave}
/>
</Show>
)}
</Resource>
Параметр keyed компонента Show как раз для этого и предназначен. При этом, в параметре when необходимо указать значение, при изменении которого произойдёт повторное выполнение.
#development #frontend #javascript #solidjs
🔥1
TypeScript + .filter(Boolean)
Тип переменной foo будет соответствовать
Обычно предлагается следующее решение:
Но есть вариант получше:
Теперь
П.С. Есть аналогичный “хак” и для Object.keys (хотя он и не совсем корректен):
#development #frontend #typescript
const numbers = [1, 2, null, void 0, 3];
const foo = numbers.filter(Boolean);
Тип переменной foo будет соответствовать
(number | null | undefined)[], хотя в действительности ни null ни undefined в массиве не будет.Обычно предлагается следующее решение:
numbers.filter((n): n is number => !!n);
Но есть вариант получше:
// global.d.ts
type Falsy = false | '' | 0 | 0n | null | undefined;
type Truthy<T> = T extends Falsy ? never : T;
interface Array<T> {
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Truthy<S>[];
}
interface ReadonlyArray<T> {
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
filter<S extends T>(predicate: BooleanConstructor, thisArg?: any): Truthy<S>[];
}
Теперь
numbers.filter(Boolean) будет возвращать number[].П.С. Есть аналогичный “хак” и для Object.keys (хотя он и не совсем корректен):
// global.d.ts
interface ObjectConstructor {
keys<T extends {}>(obj: T): ReadonlyArray<keyof T>;
}
#development #frontend #typescript
👍2🔥2
Бизнес логика vs функциональное мышление
Бизнес логика — весьма абстрактное понятие. Разработчики до сих пор продолжаются “сраться” на тему того, что считать бизнес логикой, а самое главное где она должна быть. Как один из примеров, предлагается держать бизнес логику исключительно в “умных” компонентах.
Напомню базовое определение:
> Бизнес логика — совокупность правил, принципов, зависимостей поведения объектов предметной области.
Под него подходят, как сложные вычисления на беке, так и правила по которым устанавливается размер и цвет кнопок на фронте. В данном контексте довольно сложно говорить о том, чтобы держать бизнес логику только в “умных” компонентов. При таком подходе, их количество будет стремиться к бесконечности, а для “глупых” может не остаться места.
Не знаю как вас, но меня всегда смущала эта широта трактовки бизнес логики. И сложность эта говорит о том, что возможно этот термин вообще стоит обходить стороной, и уж тем более не завязывать на него какие-то правила построения приложения.
К тому же, есть отличная альтернатива — функциональное мышление (проектирование), о котором я писал (https://t.me/around_dev/48) не так давно. Этот подход подразумевает разделение всего кода на три составляющие: данные, вычисления и действия. При этом, деление на “умные” и “глупые” компоненты прекрасно ложится на этот подход, где глупые компоненты это вычисления, а умные — действия.
#development
Бизнес логика — весьма абстрактное понятие. Разработчики до сих пор продолжаются “сраться” на тему того, что считать бизнес логикой, а самое главное где она должна быть. Как один из примеров, предлагается держать бизнес логику исключительно в “умных” компонентах.
Напомню базовое определение:
> Бизнес логика — совокупность правил, принципов, зависимостей поведения объектов предметной области.
Под него подходят, как сложные вычисления на беке, так и правила по которым устанавливается размер и цвет кнопок на фронте. В данном контексте довольно сложно говорить о том, чтобы держать бизнес логику только в “умных” компонентов. При таком подходе, их количество будет стремиться к бесконечности, а для “глупых” может не остаться места.
Не знаю как вас, но меня всегда смущала эта широта трактовки бизнес логики. И сложность эта говорит о том, что возможно этот термин вообще стоит обходить стороной, и уж тем более не завязывать на него какие-то правила построения приложения.
К тому же, есть отличная альтернатива — функциональное мышление (проектирование), о котором я писал (https://t.me/around_dev/48) не так давно. Этот подход подразумевает разделение всего кода на три составляющие: данные, вычисления и действия. При этом, деление на “умные” и “глупые” компоненты прекрасно ложится на этот подход, где глупые компоненты это вычисления, а умные — действия.
#development
🔥1
Vite vs Webpack: PURE комментарии
В продолжении поста “нюанс с React.memo” и перед темой про sideEffects хочется ещё немного накинуть про разницу в сборке проекта с помощью Vite и Webpack.
Расширим прошлый пример до:
Примечание: Из всего этого, в коде используется только компонент Test.
Собрав проект мы получаем следующие результаты:
Webpack оставил в бандле только Test и сайд эффекты, а все остальные компоненты и вспомогательные функции он удалил.
Vite же оставил всё кроме компонента TestRaw…
Ну что ж, если вы читали прошлый пост, то результат для вас ожидаем. Но возможно вас удивит тот момент, что в обоих случаях файл lazy.js (в котором лежит тот самый ленивый компонент LazyTest) присутствует в сборке. С Vite всё понятно, но почему Webpack оставил этот файл хотя компонент не используется? Давайте разбираться.
На самом деле собирается весь код до которого сборщик может дотянуться. Попутно проставляются специальные PURE комментарии-подсказки, например как в этом случае:
Далее, в дело вступает минификатор кода, именно он и удаляет всё что посчитает необходимым (что по его мнению не используется). И PURE комментарии играют в этом процессе важную роль, сообщая что следующий код “чистый” и может быть удалён, если не используется.
Но и тут Vite действует иначе… удаление не используемого кода происходит до этапа минификации (обратите внимание, он удалил константу TestMemo).
Что касается вопроса про lazy.js, то сам файл создаётся в момент сборки, а минификатор работает лишь с содержимым уже созданных файлов, поэтому файл и остаётся в бандле, хотя и не используется.
П.С. Кстати, именно поэтому анализаторы бандла могут показывать то, чего в бандле на самом деле нет.
#development #frontend #webpack #vite
В продолжении поста “нюанс с React.memo” и перед темой про sideEffects хочется ещё немного накинуть про разницу в сборке проекта с помощью Vite и Webpack.
Расширим прошлый пример до:
// Простой компонент
export { Test } from './test';
// Ещё один простой компонент
export { TestRaw } from './test-raw';
// Компонент обёрнутый в React.memo
export { TestMemo } from './test-memo';
// Компонент обёрнутый в React.forwardRef
export { TestRef } from './test-ref';
// Ленивый компонент
// через функцию поверх React.lazy
export { LazyTest } from './lazy';
Примечание: Из всего этого, в коде используется только компонент Test.
Собрав проект мы получаем следующие результаты:
Webpack оставил в бандле только Test и сайд эффекты, а все остальные компоненты и вспомогательные функции он удалил.
Vite же оставил всё кроме компонента TestRaw…
Ну что ж, если вы читали прошлый пост, то результат для вас ожидаем. Но возможно вас удивит тот момент, что в обоих случаях файл lazy.js (в котором лежит тот самый ленивый компонент LazyTest) присутствует в сборке. С Vite всё понятно, но почему Webpack оставил этот файл хотя компонент не используется? Давайте разбираться.
На самом деле собирается весь код до которого сборщик может дотянуться. Попутно проставляются специальные PURE комментарии-подсказки, например как в этом случае:
// Фрагмент из сборки от Webpack:
const TestMemo = /*#__PURE__*/(null && (memo(() => {
return /*#__PURE__*/_jsx("p", {
children: "MEMO"
});
})));
// Для сравнения, тот же фрагмент от Vite:
react.memo(() => {
return /* @__PURE__ */ jsxRuntime.jsx("p", {
children: "MEMO"
});
});
Далее, в дело вступает минификатор кода, именно он и удаляет всё что посчитает необходимым (что по его мнению не используется). И PURE комментарии играют в этом процессе важную роль, сообщая что следующий код “чистый” и может быть удалён, если не используется.
Но и тут Vite действует иначе… удаление не используемого кода происходит до этапа минификации (обратите внимание, он удалил константу TestMemo).
Что касается вопроса про lazy.js, то сам файл создаётся в момент сборки, а минификатор работает лишь с содержимым уже созданных файлов, поэтому файл и остаётся в бандле, хотя и не используется.
П.С. Кстати, именно поэтому анализаторы бандла могут показывать то, чего в бандле на самом деле нет.
#development #frontend #webpack #vite
🔥1
Комментарии в коде — “хорошо” или “плохо”?
Наткнувшись, в очередной раз, на споры о комментариях в коде, решил “зафиксировать” свои мысли на этот счёт.
Вопреки популярному мнению, заметное количество комментариев в коде — это не признак хорошего кода, а намёк на “код с душком”. Я уж молчу про примеры типа “мне тут лень было разбираться поэтому…”
В идеале, хороший код должен быть самодокументируемым. Понятные названия и типы, небольшие функции, явная структура и т.д. Комментарии действительно нужны лишь в ограниченном количестве случаев. Например, когда вы описываете публичный интерфейс, когда умышленно жертвуете читаемостью в пользу оптимизации и т.п.
В общем, комментарии — не хорошо и не плохо, это инструмент которым нужно уметь пользоваться, а не прикрывать им плохой код.
Наткнувшись, в очередной раз, на споры о комментариях в коде, решил “зафиксировать” свои мысли на этот счёт.
Вопреки популярному мнению, заметное количество комментариев в коде — это не признак хорошего кода, а намёк на “код с душком”. Я уж молчу про примеры типа “мне тут лень было разбираться поэтому…”
В идеале, хороший код должен быть самодокументируемым. Понятные названия и типы, небольшие функции, явная структура и т.д. Комментарии действительно нужны лишь в ограниченном количестве случаев. Например, когда вы описываете публичный интерфейс, когда умышленно жертвуете читаемостью в пользу оптимизации и т.п.
В общем, комментарии — не хорошо и не плохо, это инструмент которым нужно уметь пользоваться, а не прикрывать им плохой код.
👍4
Насколько React “жирный”?
Без лишней лирики, сразу к цифрам: пустое приложение на React (для веба) обойдётся вам в 187 kB пожатого js, и это только React, без каких либо дополнительных библиотек. Причём примерно 94% это react-dom-client.
Напомню, что количество js кода, это не только про скорость загрузки, но и про время парсинга, и в целом про то, как быстро будет рисоваться ваш UI.
А теперь сравним с пустым приложением на SolidJS: всего 6 kB!
Во-первых: SolidJS сам по себе компактный.
Во-вторых: он поддерживает tree-shaking (чего не может React).
Или вот реальный проект на SolidJS: 7 зависимостей (роутер и т.п.), 16 страниц, куча UI компонентов, таблицы, формы, списки и т.д., всего 702 модуля. И вот это всё весит 270 kB (233 kB без keycloak).
П.С. Пока писал, вспомнил что уже в 2015 г. были легковесные варианты React. Именно тогда и появился Preact.
Без лишней лирики, сразу к цифрам: пустое приложение на React (для веба) обойдётся вам в 187 kB пожатого js, и это только React, без каких либо дополнительных библиотек. Причём примерно 94% это react-dom-client.
Напомню, что количество js кода, это не только про скорость загрузки, но и про время парсинга, и в целом про то, как быстро будет рисоваться ваш UI.
А теперь сравним с пустым приложением на SolidJS: всего 6 kB!
Во-первых: SolidJS сам по себе компактный.
Во-вторых: он поддерживает tree-shaking (чего не может React).
Или вот реальный проект на SolidJS: 7 зависимостей (роутер и т.п.), 16 страниц, куча UI компонентов, таблицы, формы, списки и т.д., всего 702 модуля. И вот это всё весит 270 kB (233 kB без keycloak).
П.С. Пока писал, вспомнил что уже в 2015 г. были легковесные варианты React. Именно тогда и появился Preact.
🔥2
audio/ogg; codecs=opus
Если вам понадобится реализовать запись и/или воспроизведение аудио файлов
В качестве решения подойдёт npm пакет opus-recorder
https://github.com/chris-rudmin/opus-recorder
Также стоит обратить внимание на пакет wasm-audio-decoders
https://github.com/eshaz/wasm-audio-decoders
Если вам понадобится реализовать запись и/или воспроизведение аудио файлов
audio/ogg; codecs=opus, вы можете обнаружить что поддержка этой пары (контейнер + кодек) довольно скромная. Особенно грустно дела обстоят с записью, и если я правильно помню, на это способен только Firefox.В качестве решения подойдёт npm пакет opus-recorder
https://github.com/chris-rudmin/opus-recorder
Также стоит обратить внимание на пакет wasm-audio-decoders
https://github.com/eshaz/wasm-audio-decoders
Деградация кодовой базы
Ни для кого не секрет, что со временем кодовая база, практически любого проекта, так или иначе деградирует. Разрабатывать становится сложнее, задачи делаются дольше, нужно больше рефакторить и т.д. На самом деле, причин деградации кода много, и если пытаться описать их все, то получится не маленькая такая книга, а то и не одна. Так что я лишь слегка затрону этот вопрос, но с довольно важной стороны.
Если максимально упростить, деградация кода — это когда, с течением времени, код становится всё менее понятным и всё более запутанным. Отсюда можно сделать вывод, что если вы просто добавляете новый функционал и расширяете текущий, и не прикладываете дополнительных усилий для улучшения кода в целом, то ваша кодовая база уже деградирует.
На мой взгляд, одна из самых наглядных аналогий — шкаф с вещами. Сначала у вас мало вещей и всё аккуратно разложено по полкам, потом вы что-то достаёте, что-то возвращаете, и постепенно порядок превращается в кучу в которой становится сложно что-то найти. Но и это ещё не всё, время от времени вы добавляете новые вещи, а старые не выкидываете. Страшно подумать во что превратится этот шкаф со временем. 😅
А теперь давайте на это всё накинем то, что этим шкафом пользуются несколько человек одновременно. Если, при этом, нет чёткого разделения на зоны ответственности (зоны владения), то смело можно считать что никто ни за что не отвечает. А к чему приводит безответственность, я думаю, объяснять не надо.
Подытожим:
⁃ Определите зоны ответственности. В кодовой базе не должно быть “серых зон”.
⁃ Прежде чем добавить свой код, разберитесь как работает текущий. Если вам что-то не понятно, найдите автора или старшего разработчика который подскажет.
⁃ Регулярно проводите чистку. Если ваша задача связана с выпиливанием чего-либо, постарайтесь не оставлять “хвостов”.
⁃ Избегайте накопления технического долга, а в идеале следуйте правилу бойскаута: оставь место стоянки чище, чем оно было до тебя.
⁃ Старайтесь писать простой и понятный код, в конце концов 😎
И помните: Чисто не там где убирают, а там где не мусорят.
Ни для кого не секрет, что со временем кодовая база, практически любого проекта, так или иначе деградирует. Разрабатывать становится сложнее, задачи делаются дольше, нужно больше рефакторить и т.д. На самом деле, причин деградации кода много, и если пытаться описать их все, то получится не маленькая такая книга, а то и не одна. Так что я лишь слегка затрону этот вопрос, но с довольно важной стороны.
Если максимально упростить, деградация кода — это когда, с течением времени, код становится всё менее понятным и всё более запутанным. Отсюда можно сделать вывод, что если вы просто добавляете новый функционал и расширяете текущий, и не прикладываете дополнительных усилий для улучшения кода в целом, то ваша кодовая база уже деградирует.
На мой взгляд, одна из самых наглядных аналогий — шкаф с вещами. Сначала у вас мало вещей и всё аккуратно разложено по полкам, потом вы что-то достаёте, что-то возвращаете, и постепенно порядок превращается в кучу в которой становится сложно что-то найти. Но и это ещё не всё, время от времени вы добавляете новые вещи, а старые не выкидываете. Страшно подумать во что превратится этот шкаф со временем. 😅
А теперь давайте на это всё накинем то, что этим шкафом пользуются несколько человек одновременно. Если, при этом, нет чёткого разделения на зоны ответственности (зоны владения), то смело можно считать что никто ни за что не отвечает. А к чему приводит безответственность, я думаю, объяснять не надо.
Подытожим:
⁃ Определите зоны ответственности. В кодовой базе не должно быть “серых зон”.
⁃ Прежде чем добавить свой код, разберитесь как работает текущий. Если вам что-то не понятно, найдите автора или старшего разработчика который подскажет.
⁃ Регулярно проводите чистку. Если ваша задача связана с выпиливанием чего-либо, постарайтесь не оставлять “хвостов”.
⁃ Избегайте накопления технического долга, а в идеале следуйте правилу бойскаута: оставь место стоянки чище, чем оно было до тебя.
⁃ Старайтесь писать простой и понятный код, в конце концов 😎
И помните: Чисто не там где убирают, а там где не мусорят.
🔥4💩1
Не очевидный плюс сторонних пакетов, и что насчёт самописных решений
Обычно я, не то чтобы прям против, но точно не выступаю за использование таких библиотек как Axios. Есть Fetch API, и написать базовую обвязку для него, на уровне проекта, ничего не стоит (правда делать это лучше на старте проекта).
Но сегодня не об этом, а о том что у сторонних решений, помимо очевидных плюсов, есть ещё как минимум один не очевидный — «закрытость» от шаловливых ручек 🙌. К сожалению, любой код лежащий в репозитории проекта практически ни как не застрахован от изменений, в том числе негативных. Чем больше у вас проект и чем больше разработчиков над ним работает, тем выше шанс что кто-то что-то сломает, а архитектор (ну или кто там у вас ответственный, он же у вас есть, да?) даже не увидит этих изменений. И да, не все поломки очевидны и сразу исправляются.
В больших компаниях, общий функционал выносится в отдельные пакеты, в основном, чтобы не дублировать код (не писать велосипеды). Но почему-то мало кто рассматривает этот вариант с точки зрения контроля изменений критической функциональности, ну или как фильтр от поспешных решений по типу «я тут присрал, потому что у меня нет времени, нужно задачки по доске двигать».
Если вы знаете другие варианты защиты от тихих «не санкционированных» изменений, пишите в комментариях.
П.С. Если что, вариант «просто договориться» не работает. 😅
Обычно я, не то чтобы прям против, но точно не выступаю за использование таких библиотек как Axios. Есть Fetch API, и написать базовую обвязку для него, на уровне проекта, ничего не стоит (правда делать это лучше на старте проекта).
Но сегодня не об этом, а о том что у сторонних решений, помимо очевидных плюсов, есть ещё как минимум один не очевидный — «закрытость» от шаловливых ручек 🙌. К сожалению, любой код лежащий в репозитории проекта практически ни как не застрахован от изменений, в том числе негативных. Чем больше у вас проект и чем больше разработчиков над ним работает, тем выше шанс что кто-то что-то сломает, а архитектор (ну или кто там у вас ответственный, он же у вас есть, да?) даже не увидит этих изменений. И да, не все поломки очевидны и сразу исправляются.
В больших компаниях, общий функционал выносится в отдельные пакеты, в основном, чтобы не дублировать код (не писать велосипеды). Но почему-то мало кто рассматривает этот вариант с точки зрения контроля изменений критической функциональности, ну или как фильтр от поспешных решений по типу «я тут присрал, потому что у меня нет времени, нужно задачки по доске двигать».
Если вы знаете другие варианты защиты от тихих «не санкционированных» изменений, пишите в комментариях.
П.С. Если что, вариант «просто договориться» не работает. 😅
❤1✍1👎1
CSS свойство, которое работает только в Safari
Оказывается, и такое бывает. 😅 Safari — единственный (на момент написания этого поста) браузер, который поддерживает hanging-punctuation, аж с 2016 года.
Это свойство отвечает за “висячую пунктуацию”, которая широко известна в кругах профессиональных верстальщиков (тех, что верстают печатную продукцию типа журналов и т.п., а не эти ваши css + html 😎).
Висячая пунктуация — это способ набора и вёрстки текста, при котором знаки препинания, скобки, кавычки, дефисы и маркеры списков, находящиеся в начале или в конце строки, смещаются за границы основного блока текста, то есть "вывешиваются" на поля.
В общем, если типографика для вас не пустой звук, не забывайте что есть такое свойство.
Оказывается, и такое бывает. 😅 Safari — единственный (на момент написания этого поста) браузер, который поддерживает hanging-punctuation, аж с 2016 года.
hanging-punctuation: first allow-end last;
Это свойство отвечает за “висячую пунктуацию”, которая широко известна в кругах профессиональных верстальщиков (тех, что верстают печатную продукцию типа журналов и т.п., а не эти ваши css + html 😎).
Висячая пунктуация — это способ набора и вёрстки текста, при котором знаки препинания, скобки, кавычки, дефисы и маркеры списков, находящиеся в начале или в конце строки, смещаются за границы основного блока текста, то есть "вывешиваются" на поля.
В общем, если типографика для вас не пустой звук, не забывайте что есть такое свойство.
🔥2
Приколы setState в React, и как оно в SolidJS
Сравним один и тот же код изменения состояния в этих двух, похожих, но совершенно разных, библиотеках.
React:
Результат при первом выполнении: 1 2 3 4
При последующих: 1 3 2 4
SolidJS:
Результат всегда одинаковый: 1 2 4 3
А теперь, предлагаю подумать над следующими вопросами, а может и обсудить в комментариях:
- Это ожидаемый результат для вас?
- Почему такая разница в React, между первым и последующими выполнениями?
- Как добиться стабильного результата в React?
- Как добиться результата 1 2 3 4 в обоих случаях?
Сравним один и тот же код изменения состояния в этих двух, похожих, но совершенно разных, библиотеках.
React:
const [state, setState] = useState(() => Date.now());
const onClick = () => {
console.log(1);
setState(() => {
console.log(2);
return Date.now();
});
console.log(3);
};
const computed = useMemo(() => {
console.log(4);
return (new Date(state)).toDateString();
}, [state]);
Результат при первом выполнении: 1 2 3 4
При последующих: 1 3 2 4
SolidJS:
const [state, setState] = createSignal(Date.now());
const onClick = () => {
console.log(1);
setState(() => {
console.log(2);
return Date.now();
});
console.log(3);
};
const computed = createMemo(() => {
console.log(4);
return (new Date(state())).toDateString();
});
Результат всегда одинаковый: 1 2 4 3
А теперь, предлагаю подумать над следующими вопросами, а может и обсудить в комментариях:
- Это ожидаемый результат для вас?
- Почему такая разница в React, между первым и последующими выполнениями?
- Как добиться стабильного результата в React?
- Как добиться результата 1 2 3 4 в обоих случаях?
👍3