Dev News от Максима Соснова
2.8K subscribers
14 photos
1.24K links
Привет! Меня зовут Максим Соснов и по утрам я читаю всякие разные дайджесты про фронтенд, разработку и управление разработкой. Самые интересные, по моему мнению, ссылки из этих дайджестов я кидаю в этот канал с небольшим описанием.

Контакт: @msosnov
Download Telegram
GitHub - gvergnaud/ts-pattern: 🎨 The exhaustive Pattern Matching library for TypeScript, with smart type inference.

Вышла 4 версия библиотеки ts-pattern. Библиотека реализует pattern matching в TS коде. Выглядит интересно

Пример кода

import { match, P } from 'ts-pattern';

type Data =
| { type: 'text'; content: string }
| { type: 'img'; src: string };

type Result =
| { type: 'ok'; data: Data }
| { type: 'error'; error: Error };

const result: Result = ...;

return match(result)
.with({ type: 'error' }, () = `pOups! An error occured/p`)
.with({ type: 'ok', data: { type: 'text' } }, (res) = `p${res.data.content}/p`)
.with({ type: 'ok', data: { type: 'img', src: P.select() } }, (src) = `img src=${src} /`)
.exhaustive();


https://github.com/gvergnaud/ts-pattern

#link #typescript #github #library
2👍1
partykit: Everything's better with friends.

Partykit - инструментарий для разработки приложений для совместного взаимодействия в реальном времени. Как обещает описание, с этой либой легко построить свое приложение с фичей коллаборации, или добавить эту фичу в существующее приложение.

https://github.com/partykit/partykit

#development #javascript #library #github
👍5
webpro/knip: Find unused files, dependencies and exports in your JS, TS project

Knip - библиотека, которая находит неиспользуемые переменные, файлы, экспорты и зависимости в JS и TS проектах.

https://github.com/webpro/knip

#development #javascript #library #github
🤩7👍3
Dioma: Elegant dependency injection container for vanilla JavaScript and TypeScript

Dioma - новая библиотека, реализующая DI контейнеры на JS и TS. Библиотека одновременно имеет очень простое и элегантное API и при этом поддерживает разные способы инстанцирования зависимостей, разные скоупы видимости зависимостей, возможность иметь несколько контейнеров (в том числе child-контейнеры), отслеживает циклические зависимости и умеет в асинхронное инстанцирование. И все это счастье еще хорошо интегрируется с системой типов в TypeScript.

Рекомендую взглянуть на либку. Лично я, вполне вероятно, когда-нибудь её заиспользую в каком-нибудь пет проекте.

Ниже представляю пару примеров кода, чтобы было представление об API.

Использование DI в классах с применением Singletone скоупа
import { inject, Scopes } from "dioma";

class Garage {
open() {
console.log("garage opened");
}

// Single instance of the class for the entire application
static scope = Scopes.Singleton();
}

class Car {
// injects instance of Garage
constructor(private garage = inject(Garage)) {}

park() {
this.garage.open();
console.log("car parked");
}

// New instance of the class on every injection
static scope = Scopes.Transient();
}

// Creates a new Car and injects Garage
const car = inject(Car);

car.park();


Использование DI не с классами
import { Token } from "dioma";

const token = new Token<string>("Value token");

container.register({ token, value: "Value" });

const value = container.inject(token);

console.log(value); // Value


Использование фабрик
import { Token } from "dioma";

const token = new Token<string>("Factory token");

container.register({ token, factory: (container) => "Value" });

const value = container.inject(token);

console.log(value); // Value


https://github.com/zheksoon/dioma

#development #javascript #dependencyInjection #library #github #recommended
👍11🔥1
Type Predicate Generator

Подписчик канала принес ссылку на свое творение - генератор предикатов для типов. В чем суть: в typescript есть возможность писать рантайм функции, которые уточняют тип. Но писать их руками не всегда прикольно.

Например, функция, уточняющая тип до boolean - function foo(v: unknown): v is boolean { return typeof v === 'boolean' }. Выглядит просто, однако, для составных объектов уже так не получится

// example.ts
export type User = {
id: number;
login: string;
email?: string;
address: {
street: string;
house: number;
};
};


Писать руками проверки на то, что какая-то переменная является типом User - бесчеловечно (озвучивать голосом Графа Лимонохвата из Adventure Times). Для этого есть разные решения, например: библиотеки для валидации или плагины для TSC.

Type Predicate Generator, как видно из названия, использует иной подход - кодогенерацию. Вы пишете тип, указываете генератору, что хотите сгенерировать немного кода, и получаете на выходе функцию, которая проверяет тип. Более того, генератор может еще и сгенерировать юнит-тесты

Давайте разберем на примере
Для достаточно простого типа
export type User = {
id: number;
login: string;
};


Я бы написал руками что-нибудь такое:
export function isUser(arg: unknown): arg is User {
// Проверяю на объект
if (typeof arg !== 'object') {
return false;
}
// Не все объекты - объекты, выкидываем null
if (arg == null) {
return false;
}
// проверяем поля
if (typeof arg.id !== 'number') {
return false;
}
if (typeof arg.login !== 'string') {
return false;
}
return true;
}


Генератор же дает такой вывод:
import { type User } from "./example";
// used to safely get all the object attributes as `unknown`s
type SafeShallowShape<Type extends {}> = {
[_ in keyof Type]?: unknown;
};
export function isUser(root: unknown): root is User {
// check that `root` is an object
if (!(typeof root === "object" && root !== null)) {
return false;
}
(root) satisfies {};
// safely get all the attributes from `root` as `unknown`s
const { id, login }: SafeShallowShape<User> = root;
// check that `root.id` is of primitive type `number`
if (!(typeof id === "number")) {
return false;
}
// check that `root.login` is of primitive type `string`
if (!(typeof login === "string")) {
return false;
}
/*
In TypeScript the `never` type is assignable to any other type,
effectively turning it into an unsafe `any` type at assignment.
The following checks ensure that none of the checked values got
narrowed down to `never`.
*/
// @ts-expect-error: should not be `never`
(isUser) satisfies never;
// @ts-expect-error: should not be `never`
(root) satisfies never;
// @ts-expect-error: should not be `never`
(id) satisfies never;
// @ts-expect-error: should not be `never`
(login) satisfies never;
/*
Verify that all the predicates above narrowed all the types
down to the root type that is being checked by the predicate.
This is the key check that makes the whole type predicate safe.
*/
({
id,
login
}) satisfies User;
return true;
}


Плюсы генератора:
- 0 усилий
- Есть комментарии
- Корректные проверки
- Минимальные издержки в рантайме

Также можно сгенерировать unit-тесты, но тогда контент не влезет в ограничения телеги на длину сообщений :)

Можете поиграться сами в Playgroud'е

Решение интересное, имеет право на существование. Не забудьте поставить звезды автору на гитхабе.

https://github.com/peter-leonov/type-predicate-generator

#development #typescript #library #github #generator
👍18👎2
How to refactor code with GitHub Copilot

Github развивают свой Copilot и выпускают хорошие статьи по работе с ним. В данном статье рассказывается, как Copilot может помочь в рефакторинге.

Статья делится на несколько частей: что такое рефакоринг => как его начать => как сделать мелкий рефакторинг => как набросать план рефакторинга

Рефакторинг - изменение кода без изменения поведения. По сути, изменение структуры кода. Самые популярные примеры: упрощение условий, вынесение общей логики, декомпозиция функций

Перед тем как начать рефакторинг, нужно убедиться, что мы изменениями не поменяем поведение. Но для этого это поведение необходимо понять. Хорошо, когда код хорошо написан и есть комментарии - в этом случае легко погрузиться в то, как работает код. Но бывает так, что понять поведение очень сложно. Тут то на помощь и может придти Copilot - он проанализирует код и расскажет, что он делает и почему

Дальше можно перейти к простым рефакторингам. В статье предлагается очень наивный подход - просто закинуть промпт "сделай красиво"

- How would you improve this?
- Improve the variable names in this function.
- #file:pageInit.js, #file:socketConnector.js Offer suggestions to simplify this code.

Но как стартовая точка - сойдет. Вместе с Copilot можно идти в более сложные рефакторинги, когда вы накидываете контекст, а Copilot предагает решения.

Все кто использовали Copilot и ChatGPT уже, скорее всего, пробовали подход "сделай красиво". Однако команда Copilot рекомендует идти дальше и составлять план рефакторинга вместе с Copilot. Эта фича есть в Copilot Workspace и она выглядит достаточно неплохо. В чем суть: вместо того, чтобы просить Copilot сделать код красивее, можно скормить ему контекст (что делаем, зачем, какие цели, какие файлы) и попросить составить план рефакторинга. Этот план можно затем полировать вместе с Copilot, а затем уже проводить рефакторинг по плану. В целом, похоже на обычный здоровый процесс рефакторинга - перед тем как делать что-то сложное, лучше обсудить с коллегой план.

Также в статье приводится реальный кейс рефакторинга вместе с Copilot из команды Github

https://github.blog/ai-and-ml/github-copilot/how-to-refactor-code-with-github-copilot/

#development #javascript #ai #copilot #refactor #github
👍61
upfetch - advanced fetch client builder

upfetch - библиотека для удобной работы с fetch. В целом API максимально похоже на fetch, но добавлены всякие фишечки для удобства работы: таймауты, хуки, валидация, удобная передача body и query и тому подобное

Проще всего сравнить код на fetch с кодом на upfetch

Ниже примеры из ридми проекта

Отправка query-параметров
fetch:
fetch(
`https://api.example.com/todos?search=${search}&skip=${skip}&take=${take}`,
)


upfetch:
upfetch('/todos', {
params: { search, skip, take },
})



Отправка body
fetch:
fetch('https://api.example.com/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'New Todo' }),
})


upfetch:
upfetch('/todos', {
method: 'POST',
body: { title: 'New Todo' },
})



Валидация по схеме
import { z } from 'zod'

const posts = await upfetch('/posts/1', {
schema: z.object({
id: z.number(),
title: z.string(),
}),
})



Хуки

const upfetch = up(fetch, () => ({
onRequest: (options) => {
// Called before the request is made, options might be mutated here
},
onSuccess: (data, options) => {
// Called when the request successfully completes
},
onError: (error, options) => {
// Called when the request fails
},
}))


Настройка таймаута для всех запросов
const upfetch = up(fetch, () => ({
timeout: 5000,
}))



Из интересного, возможность использовать другие fetch-compatible api

import { fetch, Agent } from 'undici'

const upfetch = up(fetch)

const data = await upfetch('https://a.b.c', {
dispatcher: new Agent({
keepAliveTimeout: 10,
keepAliveMaxTimeout: 10,
}),
})


https://github.com/L-Blondy/up-fetch

#development #javascript #library #github #fetch
🔥20👍11👎1
React Scan

React Scan - инструмент, который находит проблемы в производительности React-приложений. Я не пробовал, но обещают сумасшедший DX - просто добавляете скрипт или устанавливаете браузерное расширение или запускаете cli, а инструмент вам скажет, какие конкретно компоненты требуют исправления перформанса.

Основное отличие от других существующих инструментов в том, что другие инструменты предоставляют вам способ находить ошибки, где вам нужно заниматься самостоятельным анализом, а здесь инструмент сам подсвечивает проблемы.

Гифка в ридмихе вполне себе вдохновляющая, рекомендую попробовать.

Осталось докрутить интеграцию с LLM и исходным кодом, чтоб инструмент сразу предлагал как исправить проблему

https://github.com/aidenybai/react-scan

#development #javascript #react #library #github #performance
🔥14
zshy - The no-bundler build tool for TypeScript libraries

Zshy - билд тул для typescript библиотек. Это инструментарий, который был создал для Zod, но теперь его адаптировали для широкого использования и выложили в опенсорс.

Под капотом используется tsc, сам zshy не пытается вам навязать правильный стиль написания кода, а просто собирает проект.

https://github.com/colinhacks/zshy

#development #javascript #typescript #library #github
👍2👎1
Express Slow Down

Базовое решение для защиты от повышенной нагрузки - встроить rate limiter - решение, которое будет отбивать HTTP-ошибкой на все запросы, которые идут сверх лимита.

express-slow-down - библиотека, которая предоставляет express middleware, который вместо отбивания HTTP-ошибкой как бы приостанавливает обработку запроса, давая ту же гарантию (приложение не будет обрабатывать больше Х запросов в единицу времени), но не отбивая ошибкой, а подвешивая обработку запроса.

Звучит интересно, хотя и не для всех случаев. Где-то замедлять обработку - приемлемо, а где-то - прямое ухудшение UX. Бездумно использовать не стоит, но можно задуматься о применении такого паттерна.

https://github.com/express-rate-limit/express-slow-down

#development #javascript #nodejs #express #github #library #middleware
👎2🔥2
GitHub’s internal playbook for building an AI-powered workforce

Статья от Github про сложности внедрения AI в работу. Основная проблема - не купить инструменты, а внедрить их использование в рабочий процесс.

В статье описывается модель, по которой Github масштабирует применение AI.

Основные столпы, которые необходимы для масштабирования внедрения AI:
1. AI-адвокаты — внутренняя сеть добровольцев‑чемпионов для распространения практик (как через вебинары, так и через совместную работу).
2. Понятные политики и безопасность — правила, чтобы сотрудники уверенно и безопасно использовали AI.
3. Возможность обучаться применению AI и возможность применять его в работе
4. Метрики на основе данных — система метрик по адопшену, вовлечённости и бизнес‑эффекту.
5. Ответственный, управляющий масштабированием
6. Поддержка руководства — стратегическое видение, ресурсы и тд
7. Использование подходящих инструментов — набор проверенных инструментов, подходящих под роли и задачи.
8. Внутренние сообщества (Communities of Practice) — форумы и сообщества для обмена знаниями и опытом.


В статье по каждому пункту расписано, что он из себя представляет. 2 основных столпа - это ясные политики и поддержка руководства. На основе этой поддержки работают: обучение, внедрение инструментария, ответственный за масштабирование

В статье делается большой уклон на вовлечение людей в интеграцию с AI. Не "мы придумали для вас инструменты и практики, используйте", а "индустрия меняется, будьте теми, кто участвует в ее изменении". Люди сами найдут оптимальные способы использования AI в своей работе, если их правильно вовлечь.

Также делается большая ставка на AI-адвокатов - людей, которые уже активно используют AI в работе и могут помогать внедрению AI в работу других коллег.

Также предлагается создание живого сообщества по AI-практикам - чаты, вебинары, воркшопы, где люди будут делиться своими юзкейсами и примерами.

В статье хорошо расписана ответственность того, кто отвечает за масштабирование, и за какими метриками он должен следить - начиная от "пользователи AI-инструментов в день или месяц" и до "насколько ускоряется выполнение задач с AI". Также в статье представлен чеклист внедрения модели.

Рекомендую внимательно прочитать, если вам интересна тема масштабирования использования ИИ.

https://resources.github.com/enterprise/ai-powered-workforce-playbook/

#development #ai #github
👍5
modern-tar

modern tar - библиотека для работы с tar архивами. Работает в nodejs и браузерах. Поддерживает стриминг, создание и распаковку tar-архивов.

https://github.com/ayuhito/modern-tar

#development #javascript #library #github
👍8🔥2
ffetch

ffetch - ещё одна библиотека для замены нативного fetch в коде. Эта библиотека предоставляет поддержку typescript, таймауты, ретраи с динамическим таймаутом между ретраями, хуки, менеджмент ошибок, мониторинг, circuit breaker и другие фичи. Выглядит недурно - все самое базовое и необходимое для сетевых запросов уже в комплекте.

Пример базового использования
import createClient from '@fetchkit/ffetch'

// Create a client with timeout and retries
const api = createClient({
timeout: 5000,
retries: 3,
retryDelay: ({ attempt }) => 2 ** attempt * 100 + Math.random() * 100,
})

// Make requests
const response = await api('https://api.example.com/users')
const data = await response.json()


https://github.com/fetch-kit/ffetch

#development #javascript #github #fetch
🔥181
Node.js Testing Best Practices

Репозиторий с 50+ бест практисами тестирования в Node.js. Как обычно - часть пунктов странные, часть очевидные, часть интересные. Каждый точно найдет что-то интересное для себя. Я лишь выделю пару громких интересных поинтов.

1. Всегда начинайте с интерационных тестов. E2E-тестов и юнит-тестов должно быть мало.
2. Пишите тесты во время разработки, а не после
3. Поднимайте реальную БД для тестирования с помощью докера
4. Используйте бест-практисы юнит-тестирования для интеграционных тестов
5. Структурируйте тесты по роутам и историям
6. Изолируйте компонент (в терминах Component Testing) на уровне HTTP. То есть, грубо говоря, мокайте запросы к внешним сервисам.
7. По умолчанию на все исходящие запросы надо отвечать ошибкой. Каждый тест должен явно прописывать ожидаемые ответы и запросы.
8. Не забывайте тестировать негативные кейсы, в том числе сетевые проблемы, некорректные ответы и сообщения
9. Используйте фейковый брокер сообщений для тестирования

https://github.com/goldbergyoni/nodejs-testing-best-practices

#development #javascript #nodejs #testing #bestPractices #github
👍81