progway — программирование, IT
2.68K subscribers
25 photos
1 video
246 links
Чат: @prog_way_chat

Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT

Полезности и навигация в закрепе

По всем вопросам: @denisputnov
Download Telegram
Создание собственных ошибок в приложении

С ростом приложения может быть полезно создавать собственные ошибка для удобства их обработки, лебага и логирования. В этом посте поговорим о стандартных способах как это можно сделать.

Обычно ошибки выбрасываются следующим образом:

throw Error("Ошибка сервера")


Это удобно и быстро, но с ростом приложения можно оптимизировать и это. Для этого нужно создать собственный класс ошибки:

class CustomError extends Error {
constructor(message: string) {
super(message);
this.name = 'CustomError';
}
}


Обратите внимание, что нам нужно обязательно унаследовать собственную ошибку от стандартного класса Error и вызвать конструктор родительского класса через super — это необходимые шаги для правильной инициализации собственной ошибки. this.name устанавливается для того, чтобы ошибку в логах было проще идентифицировать. Это очень полезно, но не обязательно.

Далее разберем пример создания ошибок, которые могут возникнуть в работе с API:

class NullableRequestParameter extends Error {
constructor(message = 'Required req param is nullable') {
super(message)
this.name = 'NullableRequestParameter'
}
}

class Unauthorized extends Error {
constructor(message = 'User is unauthorized') {
super(message)
this.name = 'Unauthorized'
this.code = 401
}
}

export const RestServiceError = {
NullableRequestParameter,
Unauthorized
} as const

// где-то выбросим нужную нам ошибку
throw RestServiceError.Unauthorized()


Тут мы создаём две ошибки, которые далее сможем использовать в нашем приложении. Этап с объединением под RestServiceError можно опустить, это уже мой собственный код стайл. Люблю объединять общие сущности под единым началом.

Кстати, чтобы обработать конкретную ошибку определенным способом, используется следующая конструкция:

try {
// код, где может быть ошибка
} catch (error) {
switch (true) {
case error instanceof RestServiceError.Unauthorized:
// обработка ошибки Unauthorized
break;
case error instanceof RestServiceError.NullableRequestParameter:
// обработка ошибки NullableRequestParameter
break;
default:
// обработка всех непредвиденных ошибок
}
}


Конструкция со switch (true) является более предпочтительной из-за читаемости и расширяемости, хотя можно решить ту же задачу просто через if else.

На этом всё, что я хотел описать в этой теме. Надеюсь, что это было полезно. Поддержите реакциями)

Спасибо за прочтение, это важно для меня ❤️

#web #javascript #theory #data
26👍9🔥2🐳2🍌1
Попробуем устроить интерактив 👍

Предлагаю собрать ссылки на ваши пет-проекты. Я посмотрю их, а самые частые и популярные ошибки среди всех проектов я разберу в формате постов в этом канале

Для начала ограничимся следующим:
— открытый репозиторий на площадке типа GitHub
— проект на JavaScript/TypeScript
React или проект без использования фреймворка/библиотек

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

Кстати, можно отправить несколько проектов на рассмотрение, для этого просто заполните форму несколько раз

🟢Google форма для участия

@prog_way_blog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍3🐳21
Схлопывание отступов CSS

Схлопывание отступов — механизм в CSS, при котором верхние и нижние внешние отступы двух соседних элементов могут объединяться в один отступ, если они расположены друг над другом. Это поведение может вызывать лишнее недопонимание.

Если рассмотреть ситуацию на фото, прикрепленное к посту, то можно увидеть два блока, верхний из которых имеет margin-bottom: 100px, а нижний — margin-top: 70px. Казалось бы, очевидно, что итоговый отступ между блоками будет 170px, но на самом деле это не так. В таком случае, отступы объединятся и будет выбрано и применено максимальное значение из двух: max(100px, 70px) => 100px.

Чтобы избежать схлопывания, достаточно использовать связку из разных отступов, например margin для верхнего элемента и padding для нижнего. Но такой способ я считаю всё таки костыльным. Гораздо лучше объединить два блока в родительский flex контейнер и использовать свойство gap для задания отступов между всеми элементами flex группы:

<div class="container">
<div>Верхний</div>
<div>Нижний</div>
</div>


.container {
display: flex;
flex-direction: column;
gap: 170px;
}


Такой способ гораздо более надёжный и контролируемый, а также читается легче.

Спасибо за прочтение, это важно для меня ❤️

#web #theory
37👍12🐳5🔥2🍌1🤝1
Метод массива with

withещё один новый метод массива из спецификации ECMAScript 2023, который позволяет удобно решить одну крайне специфичную задачу — изменить массив и создать его копию.

Если разбирать сразу же на примере, то выглядит это следующим образом:

const nums = [1, 2, 3, 4]
const newNums = nums.with(1, 'string')

console.log(newNums) // [1, 'string', 3, 4]


Первым аргументом метод with принимает индекс, на котором будет произведена замена, а вторым — новое значение.

Аналогом подобного метода можно считать прямую замену элемента при обращении по его индексу, только метод with не мутирует исходный массив:

const nums = [1, 2, 3, 4]
nums[1] = 'string'

console.log(nums) // [1, 'string', 3, 4]


Чтобы обойти мутацию, нам необходимо создавать отдельно копию изначального массива, а это неудобно. Метод with автоматически создаст копию за нас, что может сыграть на руку, например, в чистом redux.

Честно сказать, не смог придумать невероятно удобных кейсов применения этого метода, кроме редакса. На собесе ответить хватит и ладно. Есть и есть, чего бубнеть то.

#web #theory
👍37🐳10🔥31🍌1
progway — программирование, IT
Попробуем устроить интерактив 👍 Предлагаю собрать ссылки на ваши пет-проекты. Я посмотрю их, а самые частые и популярные ошибки среди всех проектов я разберу в формате постов в этом канале Для начала ограничимся следующим: — открытый репозиторий на площадке…
Было тяжело, но я справился…

Как и обещал пару постов выше, я посмотрел проекты, что вы прислали на ревью. Этим постом я закрываю сбор ссылок, их и так было не мало)

Я просмотрел абсолютно всё, что было прислано, каждый проект.

Что в итоге:
1. Допишу пост с общими замечаниями, которые слишком малы для отдельного поста, и опубликую его где-то через полчаса-час
2. Далее будет 9 отдельных постов с разными темами по ревью. Их буду публиковать по 3 в день, чтобы совсем не заспамить канал
3. Ну и вернёмся к тому контенту, что я публикую обычно

Приз зрительской симпатии от меня получает приложение для подготовки в ЕГЭ. Проект объективно простенький, но я в какой-то момент залип и сидел буковки тыкал. Успел накликать больше 100 слов, пока вспомнил, а зачем я там, собственно)

Что ещё важно

Я создал чат канала. Кто не знает, каналу уже сильно больше 3 лет и всё это время он существовал без публичной обратной связи — со мной можно было связаться только в личку. Сейчас же я решил создать чат, что для меня шаг достаточно важный:

1. Идея с ревью была прикольная, но я понимаю, что дать какую-то качественную обратную связь в формате постов очень тяжело. Поэтому, я надеюсь, чатик станет адекватным местом для дискуссий
2. Под постами появятся комментарии и у вас появится великолепная возможность закидать меня помидорами 💔

Ссылка на чат

Спасибо за участие, это важно для меня

@prog_way_blog#blog #review
16🔥4🐳4👍1🍌1
Общие комментарии

1. Используйте TypeScript, на современном рынке даже джуну уже не достаточно примитивных знаний TS — большинство компаний требуют хороший опыт работы с типами, понимание дженериков и прочих не самых примитивных тем

2. Выносите хотя бы ёмкие константы куда-то из файла компонента, чтобы до самого компонента не приходилось листать 100+ строк при открытии файла

3. Выносите из компонента все независимые от его состояния сущности — в константы, в утилсы и в любое другое подходящее место. Это упростит чтение кода и зафиксирует ссылки

4. Не стесняйтесь создавать свои хуки, это ок. Есть примеры, где вызов useEffect достигает 50+ строк. Вынесите/разбейте, ничего страшного в этом нет

5. Очень много непонятных закомментированных частей кода в некоторых проектах. Комментируете = не надо = удаляете, восстановить всегда можно через гит

6. Используйте index файлы для организации импортов, это делает импорты короче и читабельнее, а также позволяет проще управлять интерфейсом части кода. Используя index файл, вы явно определяете что можно импортировать, а что нельзя. Подробнее на доке

7. Аккуратнее с инлайн стилями. Их можно использовать, но очень аккуратно и в крайних случаях. ИМХО лучше !important поставить, чем инлайнить. Ну а если используйте, то не пишите стили прямо в вёрстке. 99% случаев, которые я видел, не зависят от состояния компонента, так что можно легко создать константу вне компонента и зафиксировать ссылку на объект, что может быть очень полезно и в целом разгрузит вёрстку

8. Не используйте классовые компоненты, если в этом нет явной необходимости. Мир функциональных компонентов уже непобедим

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

10. Не нужно оборачивать в memo, useMemo, useCallback абсолютно всё. В ревью видел много мест, где memo используется там, где компонент имеет 1 рендер за весь жизненный цикл и без него, а useCallback скорее замедляет приложением, чем оптимизирует

11. Можно смириться с одним тернарным оператором в вёрстке, но когда их в одной конструкции сразу два… три… такое мы рефакторим обычными if-ами)

Отдельные посты по этому ревью будут выходить с завтрашнего дня

@prog_way_blogчат#review
🔥37👍104🐳4🍌1🫡1
Использование gap вместо margin

Начнем комментарии по проектам с популярной ошибки — использование margin вместо gap. Посты постараюсь делать покороче, не хочу развозить на это всю ленту.

Почему использовать gap лучше margin:
1. Легче изменять код — чаще всего отступы везде одинаковые в таких списках. При изменении отступов, проще изменить его в одном месте, чем для каждого компонента вёрстки
2. Более чистый код, отсутствие дублирования стилей
3. Лучше производительность — браузеру куда проще обработать gap в структурированной сетке, чем нарисовать для каждого отдельного элемента собственный отступ

Что такое свойство gap
Что такое row-gap, column-gap

@prog_way_blog#web #review
👍26🔥5🐳42🍌1👀1
Файловая структура проекта

Очень важно понимать, что файловая структура — это самый верный помощник разработчика в навигации по проекту.

В некоторых проектах, что прислали на ревью, в файловой структуре бывало достаточно тяжело разобраться. Тут и pages внутри components, и другие чудеса.

Чтобы путаницы не возникало при переходе от проекта к проекту, стоит использовать общепринятые нормы оформления проектов, которые под собой подразумевают в том числе организованную файловую структуру. Для примера, это может быть FSD, который сейчас на пике популярности.

Также стоит руководствоваться просто логикой. Лично для меня не до конца понятно, когда в папку utils складывают компоненты и валидаторы, а константы в папку services

Компоненты я бы сложил к компонентам, даже если они утилитарные (пример на фото), а валидаторы в сервисы, хотя момент всё таки спорный. Лично я бы сделал что-то типа ValidatorService и разделил бы его на два дочерних сервиса: InputValidator и ModelValidator

Тут InputValidator отвечал бы, очевидно, за ввод, а ModelValidator для валидации моделей, например, валидации payload’a из ответа апишки.

Вызов самого валидатора был бы следующий:

 ValidatorService.InputValidator.email(email)


Я люблю такие оргструктуры, это мой код стайл. Кому-то он покажется странным, но его плюсы очевидны:

1. Строгая иерархичность и однозначность расположения валидаторов
2. Простой поиск того, что тебе нужно
3. Красивые импорты
4. Простое управление публичным интерфейсом сущности

Архитектурная методология Feature Slices Design

@prog_way_blog#review
👍22🐳62🔥2🍌1
Нейминг файлов

1. Определитесь в каком стиле именуете файлы. В одном проекте не должно существовать файлов MarktetTrends.jsx, filterSlice.js, table.hook.jsx. Если делаем групповой суффикс к файлу, типа *.component.jsx, то делаем везде. Если используем camelCase, то везде. Выглядит симпатичнее, искать проще, нет визуальной каши.

2. Я советовал бы переименовать table.hook.jsx в use-table.hool.jsx или use-table.jsx. Вы же знаете, что с use начинаются хуки. В поиске инстинктивно напишете use table и файл table.hook.jsx просто не найдёте. Неймингом можно спасти не одну нервную клетку, так же как и убить.

3. В названии файлов стоит избегать аббревиатур и сокращений, всегда удивляла мания экономить буквы у разработчиков. Лучше использовать только общепринятые сокращения, например, http , чтобы избежать недопониманий

@prog_way_blog#review
👍17🔥4🐳4🍌1
Линтеры

Я мог бы кучу моментов подметить на тему того, что “тут кавычки не те”, а “тут отступы кривые”. Настройте линтер. На подобные комменты в процессе ревью вообще отвлекаться — антипаттерн. Если ревью состоит из того, что вам указывают где какую кавычку лучше поставить, то это бред, а не ревью. Подобные вопросы должны решаться автоматизировано.

Другая проблема — в некоторых проектах есть eslint/prettier, супер, круто, но видно же, что код отформатирован не по ним, а в некоторых местах вообще стоят eslint-disable комменты. Пожалуйста, помимо закидывания конфиги в проект, убедитесь, что линтер реально работает и форматирует всё так, как ожидается. Ну и eslint-disable использовать тоже очевидно не нужно)

@prog_way_blog#review
👍16🐳9🔥2🤯2🍌1
Комплексные состояния

Есть такой код:

const [userData, setUserData] = React.useState<IData>({
identifier: "",
password: "",
});


Как его можно исправить:

const [identifier, setIdentifier] = useState<string>("");
const [password, setPassword] = useState<string>("");


Почему я считаю что так лучше:
1. Проще следить за иммутабельностью состояния, так как не нужно постоянно разворачивать prev объект
2. Легче контролировать зависимости и сайд эффекты, если на состояние завязывается, например, useEffect
3. Визуально в использовании считается легче
4. useState вместо React.useState, ИМХО приятнее
5. Нет необходимости создавать ещё какой-то тип

В целом, можно и так оставить то. Работать будет, и даже уже сейчас работает. Но лично мне такое бьет по глазам.

@prog_way_blog#typescript #web #review
🔥14🐳6👍2🍌1
Магические числа

Немного магии — не всегда приятно. Есть код:

date.setTime(date.getTime() + (365 * 24 * 60 * 60 * 1000));


Как можно сделать:

const MILLISECONDS_PER_YEAR = 365 * 24 * 60 * 60 * 1000;
date.setTime(date.getTime() + MILLISECONDS_PER_YEAR);


Как на самом деле нужно сделать:

const date = new Date();
date.setFullYear(date.getFullYear() + 1);


Так нужно сделать, чтобы не завязываться на число 365, так как год бывает високосным.

@prog_way_blog#review
👍28🐳32🔥2🍌2🗿2
Ответственность состояния

Есть код:

const [isFormSubmited, setFormSubmited] = React.useState({
submited: false,
submitedText: "",
submitedError: "",
submitedColor: "",
});


setFormSubmited({
submited: true,
submitedText: "Вы успешно зарегистрировались!",
submitedError: "",
submitedColor: "#238C47",
});


Как можно было бы сделать:

enum FormState {
Success,
Error,
WaitingForAction
}

const [formState, setFormState] = useState<FormState>(FormState.WaitingForAction);


Ну и в зависимости от formState рисовать любую фразу любого цвета, которого хочется. В этом случае вообще не понятно почему цвет текста и текст сообщения были вынесены в состояние. Оставьте это в вёрстке, зачем в состояние то.

@prog_way_blog#review
👍19🔥4🐳3🤔1
Страшные рефы

Есть код:

const items = [1, 2, 3, 4];
const itemRefs: React.RefObject<HTMLDivElement>[] = items.map(() =>
useRef(null),
);

// и далее в вёрстке
ref={itemRefs[index]}


Как сделал бы я:

// вынести из компонента
const items = [1, 2, 3, 4];

// внутри компонента
const itemRefs = useRef([])

// и внутри вёрстки
// index берется из .map, так как элементы на
// страницу вставляются из списка
ref={element = inputRef.current[index] = element}


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

Подробнее в официальном руководстве

@prog_way_blog#react #review
🔥11🐳92🤔1
Зачем нужен useCallback

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

Важный вопрос, будет ли ререндерится Component при ререндере родителя?

const Parent = () => {
const foo = useCallback(() => {

}, [])

return <Component foo={foo} />
}

const Component = (props) => { ... }


И ответ тут очевиден — конечно же да! Не смотря на то, что функцию мы мемоизировали и ссылка на саму функцию у нас не изменилась благодаря useCallback, мы всё равно перерендерим Component, поскольку рендерится родитель.

Чтобы получить ожидаемое поведение, необходимо сделать очень важную вещь, а именно — мемоизировать и сам дочерний компонент:

const Component = memo((props) => { ... })


Вот только так и только тогда мы перестанем ререндерить дочерние компоненты, так как пропсы не изменились. При ревью я заметил много случаев, когда useCallback использовать просто не нужно было, но он был.

А ещё много таких было кейсов:

const Component = () => {
const foo = useCallback(() => {

}, [])

return <button onClick={() => foo()} />
}


Тут смысл useCallback теряется вдвойне, так как в пропсах мы всё равно пересоздаём функцию на каждый рендер вот тут: onClick={() => foo()}

Пример из доки реакта

@prog_way_blog#react #review
👍20🐳4🔥3🤔1
Кстати, React 19 вышел в публичную бету

Серверные экшены и компоненты, новые хуки, асинхронные обработчики формы, наконец-то переработанные контексты и много чего ещё. Отдельными постами разбираем? 🐳

Пост из блога реакта — публикация от 25 апреля

@prog_way_blogчат#news
👍41🐳13😁9🔥2
Хочется делать посты чаще

Но это не так просто, потому что каждый свой пост я пишу сам, стараюсь его качественно проработать, идей не так много и всё такое. Может ввести новую рубрику в канал?

Я давно над этим думаю, но ничего невероятного в голову не приходит. Самая классная из моих идей — делать викторины по уже вышедшим постам, буду проверять ваши остаточные знания 🤓

И раз уж появился чатик, может, подискутируем на эту тему? Готов рассмотреть любую идею. "Из зала" идею взять всегда приятно, это должно быть максимально интересно для вас, а это и есть моя цель. Если стесняетесь писать в чатик, но идея есть, то напоминаю, что есть личка @denisputnov

Может быть вы чувствуете, что каналу не хватает какого-то контента?

@prog_way_blogчат#blog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍6🐳1🍌1
Лучшие практики типизации

В рамках ведения проектов и код-ревью я частенько натыкаюсь на странности написания TypeScript кода. В этом посте я постарался собрать самые частые ошибки, на которые точно стоит обратить внимание.

1. Лишний контекст
// плохо
type Person = {
personName: string;
personAge: string;
}

// замечательно
type Person = {
name: string;
age: string;
}


2. enum везде. Даже там, где не нужно.

Сила enum заключается в том, что помимо перечисления внутри контекста, enum можно использовать в качестве типа. Если вы не планируете использовать перечисления как тип, а лишь маппите что-либо в рамках одной сущности, то используйте константные объекты:
const Status = {
Success: 'success',
Fail: 'fail'
} as const;


Проблема использования enum гораздо глубже, чем может показаться на первый взгляд. Думаю, что ей можно посвятить отдельный пост.

3. Злоупотребление any. Я не противник использования any в случаях, где это действительно необходимо, но многие, даже высокого грейда разработчики, не понимают зачем конкретно он нужен. Прежде, чем воткнуть any, пожалуйста, попробуйте использовать unknown. Это сделает ваш код гораздо безопаснее.

4. Использование Definite Assertion оператора. Это когда вы утверждаете оператором восклицательного знака !, что значение точно есть, хотя оно может быть и undefined:
// так делать не нужно, лучше добавить дополнительное условие
const foo = (arg?: string) => parseInt(arg!)


5. Злоупотребление оператором as. Ровно та же проблема, что с any. Самый частый пример, что мне доводилось видеть:
type Person = {
name: string
}

// плохо
const person = {
name: "Denis"
} as Person

// замечательно
const person: Person = {
name: "Denis"
}


6. Отдельным и крайне важным для меня пунктом выделю оформление enum. Согласно всем стайл-гайдам мира, enum — сущность, группа, в единственном числе, оформленная определенным образом.
// плохо
enum OPERATION_STATUS {}
enum STATUSES {}
enum STATUS {}
enum HTTPStatus {}

// замечательно
enum OperationStatus {}
enum Status {}
enum HttpStatus {}


Обратите внимание на то, что Http я написал не капсом. Аббревиатуры в названии любых переменных оформляются именно так, а не как HTTP. Также название enum-a пишется в PascalCase. Таким же образом оформляются и ключи enum-a:
// плохо
enum Status {
SUCCESS,
FAIL
}

// замечательно
enum Status {
Success,
Fail
}


Это самые частые ошибки, что мне приходилось комментировать. Все эти правила можно прочитать в официальном TypeScript Handbook и Google JavaScript Style Guide. Это не мои выдумки — это правила, закреплённые индустрией.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#web #theory #typescript
🔥34👍156🐳2
Flash of unstyled content

Эта проблема — это тот случай, когда при загрузке страницы на долю секунды проскакивает нестилизованный контент. Как будто бы с сайта удалили все стили. И происходит это из-за того, что HTML уже построен, а стили — нет, или просто произошла ошибка при их загрузке.

Браузер уже имеет готовое DOM дерево, но всё ещё ожидает генерации CSS Object Model (CSSOM). FOUC появляется как раз до тех пор, пока не построится CSSOM. После его генерации создается дерево рендеринга и страница перерисовывается стилизованной. Выглядит это, зачастую, как вспышка белого на экране, особенно если сайт имеет какой-то специфичный фон. Отсюда и такое специфичное название.

Избежать подобной проблемы можно несколькими способами:

— Внести критический набор стилей в сам HTML, то есть описать основные стили в теге <style> в шапке index.html файла. Таким образом, мы гарантируем создание CSSOM ещё до отрисовки контента на странице, что решает проблему.

— Использовать проактивную загрузку стилей, то есть использовать preload для тега link, выглядеть это может примерно вот так:

<link rel="preload" href="style.css" as="style" />
<link rel="stylesheet" href="style.css" />


Тут мы помечаем файл style.css для предварительной загрузки, что также решает проблему.

Почему-же это важно? Всё дело в том, что наличие FOUC сильно портит пользовательский опыт, а в ночное время суток и вовсе бьёт по глазам, что вызывает отторжение у пользователей, особенно при использовании темной темы на сайте. Стилизация, в целом, играет важную роль в восприятии. Качественная работа со стилями может повысить продажи.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#web #theory
🔥39👍7🐳42
Пример тестового задания из Авито

Интересностей пост, чтобы понимать, к чему стоит стремиться новичку фронтендеру. В этом посте кратко разберу тестовое задание на стажировку из Авито 2024 года.

Вот основные требования, которые я вычленил из описания задания:
— умение использовать React, его хуки в связке с TypeScript
— умение создавать свои собственные хуки
— умение реализовать переход на другую страницу в рамках приложения
— умение работать с API и Swagger, может пригодиться axios
— умение работать с переменными окружения
— сохранение и восстановление состояния из url query параметров
— базовое понимание и настройка Webpack
— базовое понимание Node JS
— базовое понимание docker
— базовое понимание самых простых UI unit тестов

По вёрстке, необходимо уметь отображать:
— Выпадающие списки
— Изображения
— Списки компонентов

Также необходимо понимать что такое адаптивная вёрстка и уметь верстать не только для своего ПК, но и для любого другого устройства, в том числе для мобильных телефонов, планшетов и прочего.

Что важно, но в тестовом об этом не сказано:
— базовое понимание того что такое архитектура, умение строить более-менее чистую файловую структуру проекта
— грамотное использование git в процессе разработки, хотя бы не одним коммитом проект нужно заливать
— понимание того, как работают стили, как сделать более-менее симпатичный и удобный интерфейс

Напугало ли вас это? Очень надеюсь, что нет. Если подумать, то это тестовое задание очень даже не сложное. Для начинающего разработчика, который пишет 3-4 проект в жизни, очень даже реально реализовать такое за пару дней в спокойном и размеренном темпе.

Кажется, что знать нужно очень много, но очень многое из тем, что я описал выше, на достаточном для выполнения тестового уровне, изучается максимум минут за 30, а если это не первый проект в вашей жизни, то с 80% требований вы уже точно встречались и уже имели бы нужный опыт в разработке.

Полный текст тестового задания

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#web
👍31🐳63🔥2
Ну щас я проверю как вы мои посты читаете🤭

console.log(name);
console.log(age);
var name = "progway";
let age = 4;


@prog_way_blogчат#quiz
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11🐳5🗿2👍1🍌1