Результати пошуку
ITVDN: курси програмування
Відеокурси з
програмування
Підписка

300+ курсів за популярними IT-напрямками

Вибери свою IT спеціальність

Підписка
Підписка

300+ курсів за популярними IT-напрямками

Результати пошуку за запитом: mvc 5
Найкращі практики Node.JS

Автор: Редакция ITVDN

Добро пожаловать в наш небольшой сборник советов от ведущих разработчиков на платформе Node.JS! Цель сей статьи – обобщить все те знания, которые были в свое время опубликованы в различных обучающих постах или журналах. Автор статьи – Йони Голдберг, независимый разработчик и консультант Node.JS. Итак, начнем! 1) Мониторинг Что это: мониторинг – это такая интересная игра в «найти баг быстрее, чем это сделают твои пользователи». И, помимо прочего, эта игра обладает беспрецедентной важностью. Современный рынок переполнен всеми видами предложений - на любой вкус. Учитывайте: вы должны строго следовать заданной концепции, не переполняя ее различными «доп. фичами». Подберите для себя такое решение, которое удовлетворяет всем требованиям. В противном случае - провал. Разочарованные клиенты. Все просто.   2) «Умное логгирование» - Ваш друг Что это: логи, как правило, очень быстро превращаются в свалку утверждений и записей всех видов и типов. Однако при должном подходе, логи являют собой образец чистоты, легко дающие понять всю необходимую информацию, связанную с программой. Планируйте ведение логов с самого начала: как они будут собираться, храниться и анализироваться. Убедитесь, что желаемая информация (такая, как частота возникновения ошибок и прочее) в любой момент может быть легко извлечена. В противном случае: вы окончите бесконечными копаниями в нечитабельных логах и, в конце концов, потратите уйму времени на «костыли», дабы понять хоть что-то из написанного.   3) Сваливайте все возможные задачи на обратный прокси Что это: увы, но Node.JS ужасен, когда речь заходит о выполнении ресурсоемких задач на центральном процессоре (такие, как g-zip упаковка, SSL-терминация и прочее). Используйте вместо этого промежуточные middleware-сервисы, такие как nginx, HAproxy или облачные. В противном случае: Ваша невинная однопоточная операция займет процессор на длительное время. Как следствие, ваше устройство будет уделять больше времени различным промежуточным задачам, нежели непосредственно Node.JS-приложению. Не буду говорить о производительности.   4) Блокируйте зависимости Что это: код должен быть идентичен для всех сред. Однако, на удивление, можно обнаружить, что NPM творит с зависимостями что-то неимоверное – как только Вы попытаетесь установить пакет в различных средах, программа пытается использовать последнюю версию, характерную для конкретной среды, что, безусловно, вносит свои особенности. Дабы избежать этого, используйте файлы конфигурации. npmrc. Они настраивают NPM таким образом, чтобы тот сохранял текущую версию пакета, не последнюю. Как вариант Вы можете использовать “shrinkwrap”-опцию, так как NPM5 блокирует зависимости по умолчанию. В противном случае: во время тщательного теста QA пропустят версию, которая в продукции будет вести себя неожиданным для разработчика образом. Даже хуже, разные серверы одновременно в том же кластере будут исполнять разный код.   5) Выбирайте правильные инструменты: экономьте время Что это: процесс должен выполняться и перезапускаться в случае ошибок. Возможно, в обычной ситуации в качестве рестартера может сгодиться и что-то наподобие PM2, но в современном мире, где правит балом Докер и его приспешники, все подобные инструменты должны быть подобраны особенно тщательно. В противном случае: использование десятков приложений с сотнями своих инструментов в конце концов приведет к хаосу.   6) Убедитесь, что вы используете только лучшие практики отлавливания багов Что это: как правило, анализ ошибок – наиболее затратная по времени и устрашающая процедура в поддержании стабильности Node.JS-среды. В основном, причина этому – однопоточная модель приложений и отсутствие выработанной стратегии по отношению к ошибкам в многопоточной среде. Быстрых решений не существует, Вы должны в полной мере осознать и приручить это багнутое чудовище.   7) Используйте все ядра процессора Что это: в своей стандартной ипостаси приложения Node.JS используют только одно ядро процессора, в то время как остальные в задаче никакого участия не принимают. Ответственность за утилизацию всех ядер лежит только на Вас. К примеру, для небольших и средних приложений Вы можете использовать Node Cluster или PM2. Для более полновесных программ обратите внимание на репликацию процесса при помощи Docker-кластера (такие, как K8S, ECS) или деплоймент-скрипты на базе инициализации Linux (system – как вариант). В противном случае: Ваше приложение, скорее всего, будет использовать только 25 процентов доступных вычислительных ресурсов (!) или даже меньше. Заметьте, типичный сервер минимум 4-х ядерный, наивный деплой обычного NodeJS использует лишь одно (даже если Вы используете PaaS сервисы наподобие AWS beanstalk)!   8) Разумно планируйте диагностику Что это: работайте с системной информацией как с количеством используемой памяти или REPL и специальных защищенных API. Хотя полагаться на стандартные инструменты и надежней, некоторую ценную информацию и некоторые операции лучше извлекать и производить напрямую в коде. В противном случае: в один прекрасный момент Вы обнаружите, что тратите очень много информации на деплой – поставляя код в продукцию просто затем, чтобы получить некоторую информацию для диагностики.   9) Используйте APM-программы Что это: программы мониторинга вроде APM, чтобы активно оценивать кодовую базу. Посему и их действия могут выходить за рамки действий простых программ мониторинга. К примеру: некоторые APM подсвечивают проблемные транзакции, которые могут вызвать падения производительности на стороне клиента и предполагают причину подобных проблем. В противном случае: Вы можете провести тонны времени на анализ производительности и поиски проблемных мест. Вероятно, Вы так никогда и не будете уверенными, что именно замедляет работу Вашего приложения больше всего и как приложение будет вести себя в «реальном мире».   10) Завершенный код – завершенный продукт Что это: «только идеальный код может быть выпущен в продукцию». Запомните это с самого первого дня разработки. Возможно, это и звучит как что-то из репертуара законченного перфекциониста, но, поверьте, результат того стоит. В противном случае: IT-сообщество вряд ли оценит и сохранит для потомков плохо написанную систему.   11) Обращайте внимание на защиту Что это: Node.JS включает в себя некоторые уникальные защитные механизмы. Понятно и без слов, что более «защищенная» система требует больше времени на ее анализ. В противном случае: что может быть хуже, чем брешь в защите, когда продукт уже в производстве? Просто банальная проблема, которую Вы забыли исправить.   12) Отслеживайте и контролируйте память Что это: Node.JS достаточно неоднозначно работает с памятью: движок v8 обладает ограничением в виде 1.4 ГБ, и были известны случаи, когда код был излишне «памятозатратным». Потому и контроль над использованием памяти – вопрос отнюдь не тривиальный. В небольших приложениях Вы можете настраивать работу с памятью, время от времени используя команды оболочки. Однако в проектах больших масштабов позаботьтесь о выводе состояния памяти в  надежную систему мониторинга. В противном случае: вы обнаружите ежедневную «утечку» памяти в несколько сотен мегабайт, как это произошло с Walmart.   13) Разделяйте клиентскую и серверную часть Что это: для фронт-енд части используйте такие middleware компоненты, как nginx, S3, CDN и прочие. Выполнение подобных задач на Node.JS-сервере очень плохо сказывается на его производительности. Причина этому: обработка великого множества статических файлов в однопотоковой модели. В противном случае: Ваш единственный Node.JS-поток будет занят обработкой сотен html/изображений/angular/react-файлов вместо того, чтобы заняться непосредственно обработкой динамического контента. Или, другими словами, того, для чего и была разработана технология Node.JS.   14) Храните данные вне сервера Что это: сохраняйте любую информацию – будь то пользовательские сессии, кэш, загруженные файлы – на внешнем накопителе. Представляйте, как будто Ваш сервер будет регулярно «падать». Используйте «безсерверную» платформу (например, AWS Lambda). В противном случае: «падение» конкретного сервера в результате приведет не только к утилизации нерабочей машины, но и к падению производительности самого приложения. Более того, зависимость от конкретного сервера значительно уменьшит гибкость всей системы.   15) Используйте инструменты с автоопределением уязвимостей Что это: даже такие проверенные временем зависимости, как Express и другие, имеют бреши, которые время от времени могут ставить всю систему под угрозу. Однако подобное можно легко обойти, если использовать различные бесплатные или коммерческие продукты, которые постоянно проверяются на предмет уязвимостей и могут быть мгновенно исправлены в случае необходимости. В противном случае: держать код в чистоте и без уязвимостей в случае неиспользования соответствующих инструментов затребует постоянного отслеживания новостных сводок и обновлений. Немного напрягает.   16) Присваивайте каждой записи лога свой TransactionId Что это: присваивайте уникальный идентификатор каждой записи в логе. Подобный подход в значительной мере упростит работу и поиск ошибок. К сожалению, из-за асинхронной природы Node.JS реализовать подобное – задача отнюдь не тривиальная. В противном случае: Поиск производственных ошибок будет достаточно длительным. Как следствие, Вы закопаетесь в логе ко всем чертям.   17) NODE_ENV = production Что это: устанавливайте переменной окружения NODE_ENV значение production или development. Это нужно для того, чтобы указать NPM, включить ли оптимизацию или нет – так как многие подобные сервисы обладают опцией автоопределения состояния среды. В противном случае: игнорирование этого нюанса может сильно замедлить производительность. К примеру, если проигнорировать NODE_ENV, используя Express для серверного рендеринга, производительность упадет в три раза!   18) Развертывайте приложение быстро Что это: исследователи отмечают, что команды, которые проводят большее количество Node.JS-размещений, имеют меньший риск столкнуться с целым рядом проблем. Быстрые и автоматизированные размещения, не требующие рискованных ручных этапов и сервисов, в значительной мере ускоряют процесс размещения. Возможно, Вам стоит обратить свое внимание на Docker в комбинации с CI-инструментами. В противном случае: длительное размещение -> падения производительности и человеческие ошибки -> неуверенность команды -> меньшее количество размещений и, как следствие, потенциальных фич.   19) Помещайте NPM-версию в каждое размещение Что это: с каждым новым релизом указывайте в package.json-версию текущего NPM. Это внесет ясность в работе с приложением. Сей фактор важен, так как, к примеру, в среде MicroService некоторые сервисы могут обращать внимание на версию Вашего NPM. Вы можете использовать команду “npm version”, которая укажет версию автоматически. В противном случае: достаточно часто разработчики пытаются исправить баг, часто в конце обнаруживая, что они ищут его не в той версии, в которой стоило бы.   20) Следите за актуальной информацией Традиционное: отслеживайте последние обновления Node.JSб NPM и прочих технологий, с которыми Вы работаете. До новых встреч! Автор перевода: Евгений Лукашук Источник
10 заповідей Node.js розробника

Автор: Редакция ITVDN

10 отменных советов как стать лучшим Node.JS разработчиком 2018 года от автора Азата Мардана. Эта статья содержит в себе собранный и тщательно отфильтрованный опыт писателей и спикеров технологии всего Веб-сообщества. Заметка: первоначально заголовком статьи должно было быть «Лучшие практики Node.JS от Гуру Технологии». Эта статья охватывает не «новые» и «лучшие» практики 2017-2018 года, а тщательно выверенные и проверенные временем и практикой паттерны, которые стопроцентно приведут к успеху. И хотя многие из проверенных практик Вам определенно пригодятся в 2018, 2019 и даже более поздних годах, статья не включает в себя такие новшества, как async/await и прочее. Почему? Потому что эти фичи не включены в состав, собственно говоря, кода Node.JS-ядра или кода таких популярных проектов как npm, Express и прочие. Полноценно заниматься разработкой на Node.JS я начал в 2012 году, когда присоединился к Storify. С тех пор я никогда не жалел о принятом решении и не ощущал, как будто я многое потерял, закинув Python, Ruby, Java или PHP – языки, с которыми я работал на протяжении предыдущего десятилетия. Работа в компании Storify для мня оказалась достаточно интенсивной. В отличии от большинства компаний, все приложения Storify работают исключительно на JavaScript. Как вы понимаете, большинство компаний, особенно такие крупные как PayPal, Walmart или Capital One, используют Node.JS только для конкретных определенных задач. Как правило, это gateway API. Однако, с точки зрения программиста, ничего не может быть лучше, чем работа и погружение с головой в одну определенную технологию. Краткая сводка: Избегайте нагромождения – пытайтесь разбивать свой код на столько мелких составных частей, насколько это вообще возможно. И даже больше. Используйте асинхронный подход – избегайте синхронное программирование словно чумы. Избегайте блокировки потоков – помещайте ВСЕ требуемые утверждения в начало файла, ибо они синхронные и, следовательно, будут блокировать программу. Require должен быть закеширован – считайте, это такая фича в Вашем коде. Или баг. Как Вам угодно. Всегда проверяйте свой код – ошибки – это не вышивание, которое можно выбросить в любом момент. Никогда не упускайте обнаруженные ошибки! Используйте try…catch только в синхронном потоке – try…catch бесполезен в асинхронном коде. Кроме того, v8 никогда не оптимизирует try…catch-код. Возвращайте значения или используйте if…else – просто на всякий случай: возвращайте значения что бы остановить выполнение участка кода. Обращайте внимание на события ошибок – почти все Node.JS-классы или объекты реализуют паттерн-наблюдатель и производят события-ошибки. Не стоит пропускать их. Познайте свой npm – устанавливайте модули с ключами –S или –D вместо –save или –save-dev. Используйте текущие версии в package.json – при работе с npm он по-тупому просто добавляет верхнюю скобочку по умолчанию при использовании вместе с ключом –S. Дабы избежать этого, просто вручную блокируйте версии. Никогда не доверяйте semver в своих приложениях, но доверьтесь ему в модулях с открытым исходным кодом. Бонус – используйте разные зависимости. Помещайте то, что требует проект только в процессе разработки в devDependencies. После этого используйте npm i –production. Чем больше ненужных зависимостей используется, тем больше риск возникновения уязвимостей.   Давайте разберем некоторые из этих пунктов поподробнее: Избегайте нагромождения Взгляните на некоторые модули, написанные Исааком З. Шлейтером, создателем npm. К примеру, use-strict включает «строгий» режим написания JavaScript-модульного кода. Включается эта опция всего лишь в три строчки: Но почему-же все-таки стоит избегать нагромождения кода? Одна известная фраза американского воздушного флота гласит: «все должно быть просто до идиотизма». И на это существуют свои причины. Человеческий разум не может держать в памяти больше чем от 5 до 7 вещей одновременно. Это просто как факт. Разбивая код на небольшие составные части, Вы и другие разработчики легко сможете разобраться в нем и понять, для чего он предназначен. Так же упрощается процесс тестирования. Вот пример:   Или еще: Уверен, большинство из Вас отдадут предпочтение второму примеру, когда имена переменных сразу же делают понятной их суть. Конечно, в процессе написания кода Вы можете думать, что Вы понимаете, как он работает и так. Возможно, Вам даже захочется продемонстрировать свою смекалку и сообразительность, объединив несколько методов вместе в одну строку. Пожалуйста, пишите так, как если бы Вы были более неопытны. Как если бы Вы не смотрели в код на протяжении 6 месяцев, или очень устали и, кроме того, еще и выпили. Если Вы пишете код на пике своей ментальной активности, Вам будет труднее понимать его позже, не говоря уже о Ваших коллегах, которые даже не знакомы с ходом Ваших мыслей. Держать все в относительной простоте единственно верный метод – особенно в рамках Node.JS-технологии, где используется асинхронный подход. Другими словами, преимущества от использования подхода малых частей значительно более перевешивают недостатки. Помимо прочего, они позволяют значительно быстрее исправить различные ошибки, которые могут возникнуть по разным причинам в процессе работы с Node.JS-приложением.   Используйте асинхронный подход Синхронный код мало где используется в нынешнем Node.JS. Как правило, он находит свое применение в написании CLI-команд или скриптов, не связанных с веб-приложениями. Что же касательно веб-разработки, Node.JS программисты предпочитают использовать асинхронный подход, так как это позволяет избежать блокировки потоков. К примеру, синхронный код будет приемлем, если мы строит скрипт для работы с базой данных, не системы для обработки параллельных/конкурентных задач: Но, в случае веб-приложения, лучше использовать следующее: Отличительная особенность состоит в том, пишите ли вы долго исполняемый конкурентный код или небольшой скрипт с малым временем жизни. А вообще, лучше запомните одно хорошее правило: всегда пишите асинхронный код в Node.JS.   Избегайте блокировки require S обладает простой системой загрузки модулей, которая использует общий формат CommonJS. Самый простой способ подключить модули, разбросанные по отдельным файлам – использовать встроенную функцию require. В отличии о AMD/requirejs, Node/CommonJS синхронна. По сути, функция работает согласно следующему принципу: Вы импортируете то, что было экспортировано в виде модуля или файла. О чем большинство разработчиков даже не догадывается, так это о том, что require кэшируемая. Потому, до тех пор, пока нет заметных изменений зарезервированного имени файла (и, в случае использования npm-модулей, их нет), код модуля будет выполнен и подгружен в переменную только единожды (для обработки). Подобная методика позитивно сказывается на оптимизации. Однако, даже с кэширование, лучше сначала попробуйте обойтись без require. Попробуйте использовать axios-модули. Путь /connect в свою очередь будет медленнее чем требуется, ибо импорт модулей происходит после генерации запроса: Гораздо лучше будет загрузить модули тогда, когда сервер еще даже не определен, не в маршруте: Require должен быть закэширован Хотя я и упоминал о том, что require может быть закэширован, но что так же интересно, так это то, что мы можем поместить код вне module.exports. К примеру: Зная, что некоторые участки кода могут быть запущены только один раз, подобная реализация окажется более чем полезной.   Всегда проверяйте свой код Node.JS – это Вам не Java. В Java Вы выкидываете исключения потому как в большинстве случаев Ваше Java-приложение не должно продолжать работать в случае ошибки. В Java для этого Вы просто используете try…catch. В случае Node.JS история обстоит несколько по-иному. Так как технология выполняется в асинхронном режиме, контекст ошибки всегда будет отделен от любого перехватчика (такого как try…catch) в случае возникновения самой ошибки. Этот код в Node.JS будет просто-напросто бесполезен: Но! Привычный try…catch все еще может быть использован в синхронном режиме. Вот более действенный рефакторинг предыдущего участка кода: Если мы не можем обернуть request-вызов в блок try…catch, ошибка будет не перехвачена. Однако, это легко решается при помощи callback-аргумента error. Кроме того, Вам нужно всегда вручную отлавливать error в каждом и каждом callback`е. Проверяйте наличие ошибки (и убедитесь, что она не равна null) и затем, или демонстрируйте содержание ошибки пользователю или клиенту и потому логируйте ее, или отправляйте ее обратно в место вызова при помощи error-callback`а. В качестве небольшого фокуса Вы можете использовать библиотеку okay. Применяйте ее как наведено ниже что бы обойти ручной проверки на ошибки: Возвращайте значения или используйте if…else .JS – параллельный. Эта особенность может привести к багам, если не отнестись к ней с должной осторожностью. Что бы обезопасить себя, останавливайте выполнение участка кода при помощи ключевого слова return: Избегайте бессмысленной работы (и ошибок) из-за неостановленного вовремя исполнения: Просто убедитесь, что return всегда будет стоять на страже целесообразности работы Вашего кода.   Обращайте внимание на события ошибок Почти все классы/объекты Node.JS реализую паттерн-наблюдатель, который порождает событие-ошибку. Это прекрасная возможность для разработчика отловить особо подлые ошибки и придушить их до того, как они устроят хаос. В качестве полезной привычки было бы неплохо создавать программы-прослушиватели событий-ошибок при помощи использования .on(): Познайте свой npm Многие Node.JS и front-end событийные разработчики знают, что –save (для npm install) не только установит модуль, но так же и создаст запись в package.json с упоминанием текущей версии модуля. Для аналогичных целей существует и –save-dev, опция для модулей, которые нужны только во время разработки. Но знаете ли Вы, что вместо этого можно спокойно использовать –S и –D? Теперь да. И пока Вы в режиме установки модулей, удаляйте символ ^, который будут порождать команды –S и –D. Эти значки могут быть особенно опасными, так как они позволят npm автоматически обновить модуль к последней незначительной версии (вторая цифра в семантике версирования). К примеру, с версии 6.1.0 до версии 6.2.0. Команда NPM полагается на semver, но Вы не должны. Я хочу сказать, что они используют авто обновления к промежуточным версиям модулей с открытым исходным кодом, так как они полагают, что никаких радикальных изменений в этих самых промежуточных версиях не будет. Мой вам совет: не стоит слишком в это верить. Более того, используйте npm shrinkwrap. Команда создаст новый файл с текущими версиями зависимостей зависимостей. И в заключение В этом посте мы охватили много всего: от работы с callback'ами до работы с асинхронными потоками, проверки на ошибки и снятия блокировки зависимостей. Надеюсь, Вы нашли для себя что-то новое и познавательное здесь. Немного об авторе Азат является техническим консультантом и менеджером в Capital One. JavaScript/Node.js-эксперт, автор различных онлайн-курсов. Издатель более чем 12 книг, посвященных теме, включающие такие хиты продаж как Full Stack JavaScript, React Quickly, Practical Node.JS и Pro Express.js и другие. В свое свободное время Азат читает о технике на Webapplog.com, проводит конференции и работает над продуктами с открытым исходным кодом. До того, как стать экспертом Node.JS, работал в федеральных правительственных агентствах США, принимал участие в небольших старт-апах и больших корпорациях, имея дело с такими технологиями, как Java, SQL, PHP, Ruby и прочие. Азат обожает все, что связано с технологиями и финансами, так же увлекается инновационными способами обучения и просвещения людей. Автор перевода: Евгений Лукашук Источник
Java Developer: плануємо навчання правильно

Автор: Редакция ITVDN

Ваша цель - стать Junior Java developer в кратчайшие сроки? Что, если мы скажем вам, что её можно достичь всего за шесть месяцев? Хотите узнать - как? Внимательно читайте статью и следуйте рекомендациям. Мотивация  Итак, первый и, наверное, самый важный шаг – это мотивация. Как всем известно, под лежачий камень вода не течёт. Так что нужно чётко сформулировать свою цель и уже сейчас начать что-то делать для её достижения.  Но прежде чем начинать действовать, честно спросите себя: «Зачем я делаю это? Действительно ли  мне это нужно?».  Ведь без понимания значимости того или иного занятия, не будет и желания работать. Не можете понять, действительно ли это ваша цель? Лучшим мерилом того, насколько вы хотите получить желаемое, является то, что вы готовы отдать за него. Готовы ли вы тратить, допустим, 10 или 20 часов в неделю на изучение Java? Если ответ отрицательный, то с рациональной точки зрения вам следует отказаться от этой цели. Потому что, если вы уделяете этому по 5-7 часов в неделю, вы просто тратите время впустую. Аналогично и с деньгами: если вы не готовы тратить их на изучение Java, скорее всего, вы не сильно верите в то, что вам это нужно. Так что чётко определяйте цель, осмысливайте её значимость для вас и начинайте действовать!   Периоды В становлении джава-программиста условно можно выделить три периода: До резюме Во время резюме После резюме «До резюме» - это тот период, когда ещё не следует рассылать свое резюме, но создать его нужно. Резюме – своего рода рекламный буклет, в котором записаны ваши цели и желания. То есть в нём вы даёте себе чёткую задачу того, чего хотите. И чем раньше вы поймёте свои желания, тем быстрее вы получите результат. «Во время резюме» - это период, когда вы уже имеете достаточно знаний и рассылать резюме можно. На данном этапе вам следует пересмотреть ранее созданное, адаптировать его и обновить. Вообще такие действия с резюме стоит проводить раз в одну-две недели. И прежде чем отсылать резюме, его, конечно же, нужно привести в как можно более актуальное состояние. Важно отметить, что именно в этот период вы набираетесь бесценного опыта. Так как в это время вы начинаете ходить на собеседования и набивать свои первые шишки, без которых никак не обойтись. «После резюме» - период, когда вы уже устроились на работу и ни о чём не беспокоитесь. Не забываем об eXtreme Practices Для монетизации себя как специалиста, вам просто необходимо познакомиться с экстрим-практиками. «Что же это за практики такие экстремальные?» - спросите вы. Экстремального с точки зрения опасности для жизни в этих практиках очень мало. Одними из самых популярных практик считаются TVD, парное программирование, непрерывная интеграция, рефакторинг и другие. Но вы можете вырабатывать и свои практики. Просто попробуйте понаблюдать за собой в процессе работы и отметьте, что сильнее всего вам помогает в достижении конкретной цели. На базе этих наблюдений вы сможете создать практику, которая подойдёт вам наилучшим образом. Ещё один хороший способ улучшить свою работу – ретроспектива. Регулярно проводите её и анализируйте свои действия в профессиональной сфере. Пересматривайте вопросы, задаваемые вам на собеседованиях, и свои ответы на них. Это нужно делать для того, чтобы проверять себя на соответствие потребностям рабочего рынка. Вводите метрики рабочих часов, пройденных курсов или тем из них. Благодаря этому вы сможете видеть и контролировать то, сколько своих ресурсов вы потратили на обучение. Такой подход покажет вам честную картину вашей работы. Как учиться? Для освоения чего-либо существует множество возможностей. Вам только нужно найти свой способ и приступать к обучению. Давайте детально разберём несколько методов, чтобы вы смогли понять, какой из них подойдёт вам лучше всего. Онлайн тренинг В последнее время большой популярностью пользуются онлайн-тренинги. Главный их плюс состоит в том, что для них создана конкретная программа, и вы имеете доступ к ней в любое время в любом месте. Но к выбору тренинга нужно подходить с большой ответственностью. Стоит очень внимательно выбирать программу и учитывать, кто ведёт тренинг. К минусам такого метода обучения, во-первых, можно отнести большую вероятность того, что вы не пройдёте тренинг до конца, а во-вторых - отсутствие общения с тренером и такими же учащимися, как и вы. Если вы всё же решили обучаться таким способом, то верным вариантом не забросить это дело будет найти кого-то, перед кем можно будет отчитываться о проделанной работе или проходить тренинг в паре с другом. Также вы можете заключить пари с кем-то из знакомых или в социальных сетях, и тогда вам будет сложно отвертеться от начатого. Офлайн тренинг Такие тренинги ограничены местом и временем, что бывает не очень удобно, а также в большинстве своём они платные. Но посещая их, вы лучше и быстрее усваиваете материал, так как общаетесь с тренером вживую. На офлайн тренинге вы имеете возможность работать в команде над проектом, который в дальнейшем можно будет разместить, например, на GitHub и создать некую точку контакта с рекрутерами. Хотя в этом плюсе есть свои минусы, потому что если вы пропустите несколько занятий, то вам будет сложно успевать за командой. Обучаясь на офлайн тренинге, вам нужно будет готовиться к встречам, выполнять задания и приходить с вопросами к тренеру – так вы получите максимальную пользу от учёбы. На тренинге вы также имеете возможность найти напарника, с которым идти по пути к цели будет проще, или целую команду, что дает надежду на работоустройство после окончания обучения.  Платные курсы Сам факт того, что вы платите кому-то деньги, должен гарантировать некий стандарт качества и честность оказания услуг. Обычно учебные центры, в которых создаются эти курсы, заинтересованы в качестве и поддержании своей репутации. Поэтому такой способ обучения достаточно эффективен и, к тому же, существует большая вероятность того, что вы окончите курс, так как уже заплатили за него. Если вам подходит такой метод, то к выбору курса стоит отнестись осознанно и трижды подумать, прежде чем отдавать деньги. Учтите, что оплата – это благодарность авторам курса, ответственность за результат всё равно лежит на вас. Ведь каким бы хорошим не был тренер на курсе, в его обязанности не входит учиться за вас, вы должны делать это сами. Собственный проект Учиться, создавая собственный проект – это очень смело, и очень круто. Но вы должны быть готовы к любым трудностям.  Используя этот метод, для достижения успеха вам необходимо решать актуальные задачи. Начните создавать, например, консольный проект с мыслью о том, что он скоро станет веб-интерфейсом. Реализовывайте в этом проекте всю полученную вами информацию по этой теме, оттачивайте свои умения! Помните, что главное – не результат, а процесс. Потому как именно в процессе вы набираетесь знаний и опыта. Персональный коучинг При таком способе обучения с вами работает более квалифицированный специалист и решает вашу конкретную задачу. Занимаясь персонально, вы получаете индивидуальный, сделанный под вас план и выгодное знакомство. Согласитесь, никому не помешает знакомый человек из той сферы, в которой вы хотите реализоваться. Правда, у этого метода есть один минус – нанимать личного тренера зачастую стоит больших денег. Но если вы настроены серьезно и верите в поставленную перед собой цель, то это не должно быть преградой. Тренинг в компании Обучаясь в компании, вы получаете максимальный результат минимальными усилиями. Такие тренинги, как правило, бесплатные, а после их успешного окончания вы получаете возможность устроиться на работу в эту же компанию. Программы тренингов всегда адаптированы под компанию, что убережёт вас от изучения ненужного и бесполезного. Но на эти тренинги всегда очень большой конкурс, и при отборе вам необходимо проявить себя наилучшим образом. Самостоятельно Этот способ требует минимальных инвестиций и максимальной отдачи. Перед тем, как приступать к самостоятельному обучению, стоит составить учебный план. Распишите все курсы и темы, которые вы хотите пройти, распределите их по пунктам и приоритетности. Не забывайте вести учёт времени по каждому из пунктов и следить за статусом каждого из них. Выбрав самообучение, вы становитесь на непростой путь и рискуете не дойти до конца. Тем более, что сегодня вы имеете доступ к огромному количеству информации, среди которой очень просто потеряться. Но если вы всегда готовы к борьбе с трудностями и не привыкли отступать, то сможете научиться чему-либо самостоятельно. Систематически занимайтесь, создавайте свои проекты, найдите себе напарника по учёбе, и вы обязательно добьетесь успеха. Каким должен быть JavaJunior? Естественно, джуниор должен хорошо знать язык и решать алгоритмические задачи. Вы должны понимать ООП и уметь моделировать. Знание коллекций, input/output и умение писать юнит-тесты только приветствуется. Также неплохо было бы выучить какой-то из фреймворков и понимать веб-сервисы. Но это всё от вас потребуется не сразу. Некоторые из вышеперечисленных и другие навыки вы получите непосредственно в ходе самой работы.  Создание и распространение резюме В интернете вы можете найти множество советов по составлению резюме, но всё же давайте обговорим некоторые моменты, что касаются этого дела. Итак, при написании резюме вам необходимо придерживаться порядка, который присущ данному виду документа и, конечно же, писать грамотно. Свой опыт работы стоит записывать в обратном хронологическом порядке и указывать только правдивую информацию, хотя слегка её приукрасить можно.  То, что резюме нужно составлять в деловом, корректном стиле - понятно само собой. Хорошо, вы написали резюме. Теперь, чтобы начать поиск работы, вам необходимо его разослать. С этим у вас не должно быть проблем. Присылайте свое резюме известным и не очень IT-компаниям. Поместите его на сайтах поиска работы, благо сейчас таких много. Не стесняйтесь использовать социальные сети и разные сообщества для поиска работы. Главное -  быть настойчивым и не лениться, тогда всё сложиться так, как вы того хотите. Техническое собеседование Отлично! Ваше резюме подошло, и вас позвали на собеседование в компанию. Как же к нему подготовиться? В первую очередь, вы должны соответствовать требованиям вакансии и показать навыки, описанные в резюме. По возможности, просите проведения собеседования утром, так как за целый день можно забить себе голову всяким и под вечер прийти никаким. Тем более доказано, что в первой половине дня человеческий мозг работает лучше. И да, в день собеседования не вздумайте доучивать то, что не выучили раньше - это только навредит вам. Будьте спокойны, не паникуйте. Ведь беспокойство сбивает с толку и уничтожает пунктуальность. Поэтому расслабьтесь и наберитесь уверенности. На собеседовании общайтесь грамотно. Согласитесь, что человек, разговаривающий грамотно, вызывает больше доверия и вести беседу с ним приятнее. Кстати, немного о ходе беседы. Не загоняйте себя в глухой угол, не стоит говорить о тех вещах, в которых вы не разбираетесь. Этим вы можете ухудшить ситуацию и произвести неправильное впечатление.  Также следует внимательно слушать своего собеседника. Таким образом вы покажете, что умеете прислушиваться к людям и работать в команде. Вывод Всё только начинается! Если вы дочитали эту статью до конца – поздравляем! Значит, вы решительно настроены и собираетесь достичь поставленной перед собой цели.  Будьте Человеком-Решением, а не Человеком-Проблемой, и тогда перед вами откроется множество дверей. Не сворачивайте с намеченного пути, продолжайте учиться и развиваться. Помните, что всё в вашей жизни зависит только от вас. Так что уж постарайтесь сделать всё наилучшим образом.
Індексація стовпців у Redis

Автор: Редакция ITVDN

Введение В отличие от memcache, Redis может быть использован в качестве постоянного хранилища, а не только как временный кэш. Так случилось, что Redis — это невероятно быстрая база данных, дающая поразительно лучшую производительность Вашему приложению в случае правильной настройки. В качестве предостережения хотелось бы добавить, что при работе с Redis в качестве основного хранилища таится много рисков, и эти риски значительно увеличиваются в случае некорректной настройки. Настоятельно рекомендуем предварительно провести тщательное исследование Redis перед тем, как заменять Вашу текущую базу данных в пользу Redis.  Несмотря на преимущество Redis в виде невероятной скорости работы, дающейся Вашему приложению, есть факт, который стоит обязательно учесть – Redis – это фундаментальное хранилище ключей/значений, и он не поддерживает индексы. И Вы можете столкнутся с непредвиденным «челленджем» при попытке проиндексировать Ваши значения. Однако, Вы можете обойти эти ограничения с помощью удивительно полезных предоставляемых Redis типов данных. В этой статье буду рассмотрены способы использования каждых наборов и отсортированных наборов для каждого индекса, и как сортировать записи по датам, а также извлекать строки в пределах диапазона дат. О комплексных типах Redis Redis поддерживает несколько комплексных типов — списки, «сеты», отсортированные «сеты» и хэши. В текущей статье не будут упомянуты типы, за исключением «сетов» и отсортированных «сетов». Собственно, «сеты» — это коллекция уникальных неупорядоченных значений. Между тем, отсортированные сеты немного отличаются от обычных сетов. Они позволяют хранить значения, к примеру, с баллами и, таким образом, все члены отсортированного набора можно будет запросить с помощью баллов или диапазона баллов. Это может быть очень удобным при хранении, например, даты. Происходит конвертация каждого одиночного элемента (даты) и хранится в его «тике». Таким образом получается упорядоченный набор значений. Затем можно использовать команду ZRANGEBYSCORE REDIS для получения значений, которые подходят под определённый диапазон. Redis, как хранилище ключевых значений, может также хранить элемент с любым типом данных в базе данных до тех пор, пока этот элемент будет иметь уникальный ключ, определённый для него, вне зависимости от того, какого типа этот элемент – строковый или числовой.   Использование в коде Код не так страшен, как может показаться с первого взгляда. Например, целый объект сохраняется с указателем ко всем индексам. Подход таков, что объект может быть сохранён, как скалярная строка с id в различных индексах. В коде есть класс «Person», позволяющий сохранять объекты класса «Person» с параметрами, например, имя, пол, страна проживания и дата рождения. Класс написан достаточно просто, на мелкие детали не придётся обращать внимание. Также в коде есть статический класс «RedisAdaptor», который содержит в себе вспомогательные функции для сохранения класса «Person» и вызова его объектов. Основная программа В основной программе имеется цикл, который прогоняется ежедневно на протяжении указанного года – 1971 и создаёт новый объект класса «Person» с указанием даты рождения. В случае с полом мы оставляем один единственный объект с указанием женского или мужского пола. Для страны (учитывая, что определены только 3 страны) каждый объект класса «Person» проживает в Индии, США и Англии. В качестве имени используется строка, генерируемая случайным образом. static void Main(string[] args) {     const int YEAR = 1971;     // We create one Person object for every single day in the given year.     for (int month = 1; month <= 12; ++month)     {         for (int day = 1; day <= 31; ++day)         {             try             {                 // Get any random name:                 string name = Util.GetAnyName();                 // And a DoB:                 DateTime dob = new DateTime(YEAR, month, day);                 // As for the gender, let's alternate:                 Gender gender = Gender.FEMALE;                 if (day % 2 == 0)                 {                     gender = Gender.MALE;                 }                 // And the country, let's round-robin between all three:                 Country country = Country.INDIA;                 if (day % 3 == 1)                 {                     country = Country.USA;                 }                 else if (day % 3 == 2)                 {                     country = Country.GB;                 }                 // Create a new Person object:                 Person person = new Person(name, gender, country, dob);                 //Console.WriteLine ("Created new Person object: {0}", person);                 // We call the function that will store a new person in Redis:                 RedisAdaptor.StorePersonObject(person);             }             catch (Exception)             {                 // If the control reaches here, it means the date was illegal.                 // So we just shrug your shoulders and move on to the next date.                 continue;             }         }     }     // At this point, we have 365 Person objects as a sorted set in our Redis database.     // Next, let's take a date range and retrieve Person objects from within that range.     DateTime fromDate = DateTime.Parse("5-May-" + YEAR);     DateTime toDate = DateTime.Parse("7-May-" + YEAR);     List persons = RedisAdaptor.RetrievePersonObjects(fromDate, toDate);     Console.WriteLine("Retrieved values in specified date range:");     foreach (Person person in persons)     {         Console.WriteLine(person);     }     // Next, let's select some folks who are female AND from the USA.     // This calls for a set intersection operation.     List personsSelection = RedisAdaptor.RetrieveSelection(Gender.FEMALE, Country.USA);     Console.WriteLine("Retrieved values in selection:");     foreach (Person person in personsSelection)     {         Console.WriteLine(person);     } } В классе «Redis Adaptor» есть одиночная функция, используемая для хранения и индексации значений, прошедших через него, и функция для запрашивания значений по диапазонам дат, полу и стране. Также в программе имеется несколько статических полей и констант для данных. Учтите, что индексация уже произошла в процессе сохранения. В этом участке мы проиндексировали пол, страну и дату рождения. static class RedisAdaptor {     const string REDIS_HOST = "127.0.0.1";     private static ConnectionMultiplexer _redis;     // Date of birth key:     const string REDIS_DOB_INDEX = "REDIS_DOB_INDEX";     // Gender keys:     const string REDIS_MALE_INDEX = "REDIS_MALE_INDEX";     const string REDIS_FEMALE_INDEX = "REDIS_FEMALE_INDEX";     // Country keys:     const string REDIS_C_IN_INDEX = "REDIS_C_IN_INDEX";     const string REDIS_C_USA_INDEX = "REDIS_C_USA_INDEX";     const string REDIS_C_GB_INDEX = "REDIS_C_GB_INDEX";     static RedisAdaptor()     {         // First, init the connection:         _redis = ConnectionMultiplexer.Connect(REDIS_HOST);     }     public static void StorePersonObject(Person person)     {         // We first JSONize the object so that it's easier to save:         string personJson = JsonConvert.SerializeObject(person);         //Console.WriteLine ("JSONized new Person object: {0}", personJson);         // And save it to Redis.         // First, get the database object:         IDatabase db = _redis.GetDatabase();         // Bear in mind that Redis is fundamentally a key-value store that does not provide         // indexes out of the box.         // We therefore work our way around this by creating and managing our own indexes.         // The first index that we have is for gender.         // We have two sets for this in Redis: one for males and the other for females.         if (person.Gender == Gender.MALE)         {             db.SetAdd(REDIS_MALE_INDEX, personJson);         }         else {             db.SetAdd(REDIS_FEMALE_INDEX, personJson);         }         // Next, we index by country.         if (person.Country == Country.INDIA)         {             db.SetAdd(REDIS_C_IN_INDEX, personJson);         }         else if (person.Country == Country.USA)         {             db.SetAdd(REDIS_C_USA_INDEX, personJson);         }         else if (person.Country == Country.GB)         {             db.SetAdd(REDIS_C_GB_INDEX, personJson);         }         // Next, we need to create an index to be able to retrieve values that are in a particular         // date range.         // Since we need to index by date, we use the sorted set structure in Redis. Sorted sets         // require a score (a real) to save a record. Therefore, in our case, we will use the         // DoB's `ticks' value as the score.         double dateTicks = (double)person.DoB.Ticks;         db.SortedSetAdd(REDIS_DOB_INDEX, personJson, dateTicks);     }     public static List RetrievePersonObjects(DateTime fromDate, DateTime toDate)     {         // First. let's convert the dates to tick values:         double fromTicks = fromDate.Ticks;         double toTicks = toDate.Ticks;         // And retrieve values from the sorted set.         // First, get the database object:         IDatabase db = _redis.GetDatabase();         RedisValue[] vals = db.SortedSetRangeByScore(REDIS_DOB_INDEX, fromTicks, toTicks);         List opList = new List();         foreach (RedisValue val in vals)         {             string personJson = val.ToString();             Person person = JsonConvert.DeserializeObject(personJson);             opList.Add(person);         }         return opList;     }     public static List RetrievePersonObjects(Gender gender)     {         // First, get the database object:         IDatabase db = _redis.GetDatabase();         string keyToUse = gender == Gender.MALE ? REDIS_MALE_INDEX : REDIS_FEMALE_INDEX;         RedisValue[] vals = db.SetMembers(keyToUse);         List opList = new List();         foreach (RedisValue val in vals)         {             string personJson = val.ToString();             Person person = JsonConvert.DeserializeObject(personJson);             opList.Add(person);         }         return opList;     }     public static List RetrievePersonObjects(Country country)     {         // First, get the database object:         IDatabase db = _redis.GetDatabase();         string keyToUse = REDIS_C_IN_INDEX;         if (country == Country.USA)         {             keyToUse = REDIS_C_USA_INDEX;         }         else if (country == Country.GB)         {             keyToUse = REDIS_C_GB_INDEX;         }         RedisValue[] vals = db.SetMembers(keyToUse);         List opList = new List();         foreach (RedisValue val in vals)         {             string personJson = val.ToString();             Person person = JsonConvert.DeserializeObject(personJson);             opList.Add(person);         }         return opList;     }     public static List RetrieveSelection(Gender gender, Country country)     {         // First, get the database object:         IDatabase db = _redis.GetDatabase();         string keyToUseGender = gender == Gender.MALE ? REDIS_MALE_INDEX : REDIS_FEMALE_INDEX;         string keyToUseCountry = REDIS_C_IN_INDEX;         if (country == Country.USA)         {             keyToUseCountry = REDIS_C_USA_INDEX;         }         else if (country == Country.GB)         {             keyToUseCountry = REDIS_C_GB_INDEX;         }         RedisKey[] keys = new RedisKey[] { keyToUseGender, keyToUseCountry };         RedisValue[] vals = db.SetCombine(SetOperation.Intersect, keys);         List opList = new List();         foreach (RedisValue val in vals)         {             string personJson = val.ToString();             Person person = JsonConvert.DeserializeObject(personJson);             opList.Add(person);         }         return opList;     } } Каждый ключ константы определяется в статическом классе, как, например, REDIS_DOB_INDEX, REDIS_MALE_INDEX, REDIS_FEMALE_INDEX и остальные,  всё это – ключи к индивидуальным сетам в хранилище Redis. Однажды, когда мы сохранили значения и создали индексы для сетов в Redis, мы сможем запрашивать их, используя различные версии перегруженных функций RetrievePersonObjects с параметрами – диапазоном дат, полом и страной. Запрос по полу достаточно прост: основываясь на определении пола, мы «погружаемся» в один из двух гендерных сетов и получаем запрошенное значение. Точно та же процедура используется в отношении индекса стран. Чтобы извлечь значения диапазона дат, используется метод SortedSetRangeByScore в объекте базы данных. Он принимает три аргумента: первый – имя сортированного сета, минимальные и максимальные значения. Ещё одна интересная фича в работе с сетами Redis – великолепные семантические сеты. С их помощью можно определять два и более сетов, в результате чего БД Redis делает объединение, пересечение или определяет разность сетов. В последней секции кода посмотрите на функцию снизу – «RetrieveSelection», которая декларирует два параметра – пол и страна. Эта функция соответственно возвращает два параметра – пол и страну. Источник: http://www.codeproject.com/Articles/1072137/Indexing-Columns-in-Redis
ТОП-10 найкращих відео з Python

Автор: Влад Сверчков

Вітаємо! Друзі, цього разу ми підготували для вас підбірку найкращих вебінарів від ITVDN за напрямком Python. До рейтингу увійшли як пізнавальні вебінари з актуальною інформацією, так і вебінари, орієнтовані на прокачування ваших навичок створення коду. Давайте приступимо до їх розгляду.     Пишемо API додаток на Python за допомогою FastAPI та Docker   Автор – Антон Козаченко, Python Back-end Developer з Латвії   На вебінарі автор розбирає приклад написання API додатку на Python за допомогою фреймворку FastAPI та інструменту Docker. Розглядається фреймворк FastAPI, також створюється декілька методів API. Автор розглядає Docker, пише свою конфігурацію та запускає контейнери. Додатково відбувається покриття API додатку тестами.   План вебінару:   Ознайомлення із фреймворком FastAPI. Написання кількох endpoint-ів API. Написання тестів для цих endpoint-ів. Написання конфігурації для Docker. Запуск додатку в Docker containers. Запуск тестів.     2. Підготовка до технічної співбесіди з Python ➤ Як пройти співбесіду на Junior Python?   Авторка – Людмила Міщенко, Python розробниця   Вебінар присвячений ключовим моментам технічної співбесіди на позицію Junior Python Developer. Розглядаються найчастіші питання, логічні та технічні завдання. Ви дізнаєтесь, як правильно готуватися до співбесіди. Приділено увагу тому, як отримати користь від проходження технічного інтерв'ю та як залишити приємне враження про себе у спеціалістів компанії. Також автор порушує теми важливості роботи над помилками та аналізу співбесіди.   План вебінару:   Як готуватися до технічної співбесіди? На які запитання має знати відповідь Junior Python Developer? На що у відповідях кандидатів найбільше звертають увагу? Чи потрібні (і яку роль грають) pet-projects для фахівця-початківця? Як не розгубитися під час кодингу на співбесіді? (+ поради та лайфхаки) Робота над помилками та аналіз фідбеку після співбесіди.     3. Що краще: Django, Flask чи FastAPI? Огляд фреймворків для веб-розроблення на Python.   Автор – Максим Кузнєцов, Senior Python Developer   В даному вебінарі розглядаються декілька популярних веб-фреймворків на Python (Django, Flask, FastAPI). Автор порівнює їхню продуктивність і пояснює, для яких цілей який фреймворк більше підійде.   План вебінару:   Огляд Django та його фічі. Огляд Flask та його фічі. Огляд FastAPI та його фічі. Порівняння продуктивності. Коли який фреймворк вигідно застосовувати. Відповіді на питання.   Даний вебінар буде цікавий Python розробникам-початківцям, і тим, хто збирається перейти на Python і хоче спланувати своє навчання з урахуванням особливостей різних інструментів.     4. Створення гри BlackJack на Python з нуля (Частина 1 та Частина 2)   Автор – Артем Мураховський, Python Developer, тренер-консультант CyberBionic Systematics   "Створення гри BlackJack на Python" – це дводенний інтенсивний тренінг зі створення відомої карткової гри. Вебінар покликаний у захоплюючій формі познайомити новачків з Python та попрактикуватися у написанні коду цією мовою. Мінімум теорії та максимум практики – що ще потрібно для швидкого старту в програмуванні?   Чому можна навчитися, вивчивши відео матеріали тренінгу та випробувавши отримані знання на практиці:   Писати просту програму мовою Python Розбивати завдання на дрібні підзадачі та успішно їх вирішувати Проєктувати архітектуру програм Писати програми на рівні класів Розв'язувати алгоритмічні задачі Розуміти призначення патернів проєктування   План першого відео (першої частини):   Знайомство із середовищем розроблення PyCharm та мовою програмування Python. Розбір основних елементів мови. Створення архітектури програми на рівні класів. Поліпшення архітектури з використанням патернів. Створення перших об'єктів.   План другого відео (другої частини):   Створення структури проєкту. Наслідування та композиція. Створення спеціальних типів даних. Зв'язок компонентів між собою. Тестування. Підбиття підсумків.     5. Об'єктно-орієнтоване програмування в Python ➤ Що таке ООП та як воно працює.   Автор – Бондаренко Кирило, Data Scientist / Python Developer, "CreatorIQ"   Об'єктно-орієнтоване програмування (ООП) – дуже важлива парадигма у сучасному програмуванні. Цей вебінар розкриває основні принципи ООП і показує, як вони реалізовані у мові Python.   Наскільки важливим є знання ООП для Python розробника? Як часто доводиться використовувати ООП у роботі? У яких проєктах, у яких завданнях? Чи візьмуть вас працювати без знання ООП? Ці та інші питання будуть поставлені в даному вебінарі.   Теми, що розкриваються:   Що таке ООП і як це працює у Python. Приклади розв'язання задач через ООП. Підбиття підсумків. Відповіді на питання.     6. Створення чат-бота "прогноз погоди" на Python   Автор – Артем Мураховський, Python Developer, тренер-консультант CyberBionic Systematics   Якщо ви хочете випробувати свої сили в програмуванні на Python і створити власного Telegram-бота, який сповіщатиме вас про актуальну погоду, цей відеоролик буде дуже доречним.   Підійде як новачкам, які ніколи не програмували, так і розробникам-початківцям, які бажають поглибити і застосувати на практиці свої знання Python.   План:   Рівні моделі мережі Інтернет. Що таке бібліотеки на Python. Що таке API. Telegram API. Бібліотеки для Telegram API. Робота з чистим API.   Чого ви навчитеся:   Реалізовувати нескладну програму мовою Python, яка прогнозуватиме погоду. Основам базового синтаксису мови Python. Теоретичним основам API – зрозумієте, як він працює. Працювати із запитами. Створювати роботів для месенджеру Telegram. Використовувати існуючі сервіси для прив'язки до вашої програми.     Автоматизація парсингу сайтів на Python   Автор – Артем Мураховський, Python Developer, тренер-консультант CyberBionic Systematics   В епоху машинного навчання інформація стає нафтою XXI століття. Проєкти, пов'язані зі збором та аналізом даних, виходять на перші позиції у глобальних компаніях та в стартапах.   Як збирати та обробляти інформацію? Залежно від цілей проєкту, дані можуть збиратися абсолютно різні. На вебінарі ми розглянемо один із найпоширеніших підходів – парсинг сайтів.   Ми візьмемо один із популярних сайтів з робочими вакансіями та на його прикладі розберемо бібліотеки для парсингу веб-сайтів, бібліотеки для роботи із запитами. Розберемо види популярних баз даних і зрозуміємо, де і яку потрібно використовувати.   План вебінару:   Що таке парсинг веб-сайтів? Бібліотеки для парсингу веб-сайтів. Бібліотеки для роботи із мережею. Написання коду парсерів. SQL та NoSQL – за яких завдань який тип використовується. Написання коду менеджерів баз даних.     8. Створення простої казуальної гри на Python   Авторка – Людмила Міщенко, Python розробниця   На вебінарі буде розглянуто реалізацію простої гри на Python. Суть гри полягає у навчанні людей, особливо дітей, вести еко-дружній спосіб життя – правильно сортувати сміття. Тобто, користь буде не тільки для вас у отриманні нових знань у програмуванні, а й у спробі виявити більше турботи про нашу планету.   План вебінару:   1. Постановка задачі.   а) Мета вебінару – створити свою гру на Python, яка вчить сортувати сміття; б) правила гри – обирати правильний кошик для різного типу сміття; закінчення гри за таймером; наприкінці гри користувач отримує суму зароблених балів за правильно обрані кошики.   2. Реалізація програми:   а) встановлення модулів; б) завантаження потрібних зображень; в) написання логіки влучення сміття в кошик (поведінка кошика); г) оголошення та опис елементів сміття (органіка, пластик, папір) – клас поведінки сміття; д) виклик написаних класів та запуск гри.   3. Отримання результатів:   а) запуск та тестування коду; б) проходження гри; в) аналіз виконаної роботи – додавання та зміна умов гри, оптимізація коду, майбутні доопрацювання.       9. Структури даних у Python. Рівень Advanced   Автор – Бондаренко Кирило, Data Scientist / Python Developer, "CreatorIQ"   Якщо ви маєте труднощі з розумінням документованих структур мови Python, таких як list, tuple, dict, set, цей вебінар для вас. Ми розбиратимемося з тим, як написати такі структури даних, як черги (queues), дерева (trees), розглянемо роботу зі вкладеними словниками (nested dicts), а також застосування ООП для розширення можливостей існуючих структур даних.   Матеріал цієї зустрічі буде корисний Python розробникам із різних областей, зокрема Data Science спеціалістам та web-розробникам.   План вебінару:   Робота з розширенням структур даних мови через наслідування та ООП. Робота з комбінованими структурами, такими як nested dict, defaultdict, named tuple і т. д. Написання незадокументованих структур даних, таких як дерева, черги, зв'язані списки та інші.   Цей вебінар буде цікавий розробникам, які добре знайомі з Python, знають про імпорт бібліотек і хочуть заглибитися в роботу зі структурами даних для більшої ефективності роботи з ними.     10. Як стати Python розробником у 2021 році?   Автор – Артем Мураховський, Python Developer, тренер-консультант CyberBionic Systematics   В останні роки мова програмування Python стрімко набирає популярність. За даними Stack Overflow Developer Survey 2019, в якому взяли участь понад 87 тисяч IT-фахівців з різних країн, Python випередила навіть таких постійних та безперечних лідерів, як Java, С# та С++.   Зараз вона широко використовується в Data Science (машинне навчання, аналіз даних, візуалізація), розробленні вбудованого програмного забезпечення та реалізації серверної частини веб-додатків. Також за допомогою Python можна створювати ігри, десктопні та мобільні програми, писати тести для ПЗ та спрощувати адміністрування ОС.   Програма зустрічі:   Хто такий Python розробник і що він робить? Які знання, вміння та навички потрібні Python розробнику? Вимоги до розробників рівня Junior. З чого розпочати вивчення мови Python? Складання плану навчання. Рекомендована література. Відповіді на питання.   Вивчайте Python розроблення на ITVDN!
Міфи про програмування та програмістів

Автор: Влад Сверчков

Миф 1. Без знания математики дверь в программирование закрыта Миф 2. “Прочту книгу — стану программистом” Миф 3. Чтобы освоить программирование, необходимо быть очень умным Миф 4. Необходимо обладать талантом к написанию кода Миф 5. Программисты — замкнутые и необщительные люди Миф 6. Программирование — скучное занятие Миф 7. Программисты всё пишут с нуля Миф 8. Чтобы устроиться на работу в качестве программиста, необходимо очень долго учиться Миф 9. После курсов у вас сразу высокая ЗП Миф 10. “Выучи язык программирования… за 1 час!” Миф 11. Нельзя освоить программирование самостоятельно Миф 12. Программисты разбираются во всём, что связано с техникой Миф 13. Программирование — мужское занятие Миф 14. Существует самый-самый лучший языка программирования Миф 15. Разработчики компьютерных игр — самые богатые и счастливые люди в IT Миф 16. Начинающим айтишникам устроиться на работу невозможно Миф 17. Пойду в ВУЗ, там меня научат программированию Миф 18. Программирование имеет возрастные ограничения Миф 19. Программист — вымирающая профессия: роботы заменят этих специалистов Итоги   Приветствуем вас, друзья! При своей относительной молодости программирование успело обзавестись приличным количеством мифов. Время, когда писателей кода считали дикими отшельниками, потихоньку уходит. Однако, и по сегодняшний день многие имеют ложные представления о программировании. Некоторые считают, что программист - это человек, который взламывает компьютерные системы, банкоматы и совершает прочие несогласованные с буквой закона действия. Другие уверены: программист и компьютер тебе починит, и Windows переустановит, и ТВ-каналы настроит, и новый Фейсбук за ночь напишет, и покажет, как генерировать содержание документа в Ворде.  Более того, некоторые стереотипы настолько прижились, что стали отпугивать новичков в IT и мешать их профессиональному дебюту в данной сфере. Мы подготовили для вас рейтинг самых главных мифов, которые необходимо развеять в первую очередь. Давайте же приступим к их разрушению.   Миф 1. Без знания математики дверь в программирование закрыта Одно из самых распространенных заблуждений. Как мы уже упоминали в статьях “Нужно ли программисту высшее образование?” и “FAQ начинающего программиста”, важно не столько знание математики напрямую, сколько само математическое мышление. Сейчас мы все объясним. Для того, чтобы начать изучение любого популярного языка программирования (ЯП), с головой хватит знаний школьной алгебры. Согласно опросу Stack Overflow Developer Survey 2020, более 50% разработчиков-респондентов написало свою первую строку кода до 16 лет, а в этом возрасте никто еще не изучает высшую математику. Значит, сделать старт в программировании может любой, кто учился/учится в обыкновенной среднестатистической школе. Это первая ступенька на пути к качественному овладению ЯП. Когда вы начнете более-менее ориентироваться в языке и поднабьете руку на практических задачках, вам необходимо будет изучить смежные с математикой дисциплины: теорию множеств, графов, автоматов, алгоритмов, базовую логику. Это программа первых курсов технических вузов по IT-направлению, однако и самостоятельное ее освоение — вполне подъемная задача. При этом наименее зависимыми от математики являются такие специальности, как верстальщик и FrontEnd разработчик. Хорошие знания в области высшей математики необходимы тем, кто хочет реализовать себя в таких направлениях: научная область, шифрование, машинное и глубокое обучение, Data Science, разработка искусственного интеллекта и все, что связано с большими данными. Именно там находит широкое применение тот мат. аппарат, которым славятся технические вузы. Математика в программировании — это, прежде всего, о математическом и аналитическом мышлениях, которые тесно связаны с критическим мышлением и позволяют абстрагироваться, развязывать задачи с умелым применением логики. Именно правильный взгляд и рациональный подход к решению задач является главным оружием программиста, поскольку программирование — это динамика, в то время, как формулы, теоремы и аксиомы статичны. С развитием мат. мышления вам помогут различные книги, а также практика — кодинг, решение математических задачек и прочие упражнения, которые можно найти на просторах интернета. Кстати, критическое мышление отлично развивают шоу с фокусниками. Посмотрите их, подумайте над тем, как маэстро смог провернуть тот или иной трюк (затем посмотрите соответствующие разоблачения). Также будут полезны детективные игры в стиле “Шерлока Холмса”, где, казалось бы, мистическим событиям находяться вполне логические объяснения. Умение не принимать всю информацию как чистую правду, а смотреть на нее со всех возможных углов — очень полезный навык не только в кодинге, но и в повседневной жизни.   В любом случае, данный миф о математике разрушен, а это означает, что начать программировать вы можете прямо сейчас.   Миф 2. Можно стать программистом, просто прочтя одну или несколько книг (“Прочту книгу — стану программистом”) Программирование — это в большей степени практика. Теория здесь обязательно должна подкрепляться добротным кодингом. Это обеспечит закрепление полученной информации, а также будет гарантировать понимание вами материала и способствовать развитию ваших навыков написания кода. Поэтому чтение книг начинающими программистами должно обязательно сопровождаться соответствующими отработками (практикой), иначе получите ноль пользы от литературы и только зря потратите свое время, не достигнув желаемого.    Миф 3. Чтобы освоить программирование, необходимо быть очень умным Миф, который отпугивает множество потенциальных программистов. Появился он из-за ложного убеждения, мол, программисты — это сверхразумы, которые видят мир, как в “Матрице” — в форме бесконечно бегущих зеленых символов. На самом деле они обыкновенные люди. Просто они горят кодом. Программистам нравится создавать компьютерные программы, веб-сервисы, игры, мобильные приложения. Точно так же экстремалам-байкерам нравится выделывать различные трюки на железном коне, знатокам поварского дела — готовить вкусные и красивые блюда, летчикам — поднимать в воздух многотонные крылатые гиганты, водителям — колесить по бескрайним просторам, психологам — помогать людям понимать себя. Если посмотреть на каждую профессию со стороны, в каждой можно найти свои сложности. И каждое препятствие преодолевается прежде всего большим трудом и упорством. А мозги — это часть организма, которая поддается прокачке, как и мышцы тела. Поэтому если вы чувствуете, что “недостаточно умны” для программирования, начинайте ломать этот барьер, работайте над собой и ни в коем случае не позволяйте каким-либо предубеждениям вставать у вас на пути. Никто этот шаг за вас не предпримет, так что все в ваших руках.       Миф 4. Необходимо обладать талантом к написанию кода Успех программиста как такового обусловлен его заинтересованностью выполняемой задачи, количеством специализированных знаний, степенью владения ЯП и математическим мышлением, а также прилагаемыми усилиями. Таланта или какого-то дара в перечне нет. Так что программирование — это 95% усердной работы. Не ожидайте манны небесной — работайте, трудитесь и тогда вы сможете преуспеть в создании кода.   Миф 5. Программисты — замкнутые и необщительные люди Возможно, в далеком прошлом это и было правдой, однако сейчас все совершенно по-другому. Более того, одними из главных требований к личным качествам программистов сегодня являются коммуникабельность, открытость и умение работать в команде. Время компьютерных гиков-одиночек кануло в Лету. Различные конференции, хакатоны, совместный отдых и развлечения — эти вещи как-то мало совместимы с замкнутостью и необщительностью, вы не находите? Такой спектр коммуникабельности не всегда можно встретить в фирмах, которые специализируются на коммуникациях с клиентами, а тут целые мероприятия, куда разработчики приходят пообщаться, заиметь новые связи, обменяться опытом и просто отдохнуть.    Миф 6. Программирование — скучное занятие На первый взгляд это правдоподобно: человек сидит перед монитором (или несколькими), набирает строчки кода и так целый день напролет. Ну что тут может быть интересного? Даже как-то страшно становится... Однако, это очень урезанный взгляд на то, чем занимается программист. Прежде всего, в рассматриваемой ситуации он может: разрабатывать одну из механик компьютерной/мобильной игры; создавать мобильное приложение; реализовывать привлекательный внешний вид веб-сайта; разрабатывать программу для какого-то “умного” устройства; работать над автоматизацией каких-то рутинных процессов, которые обыватели проделывают чуть ли не каждый день; писать программное обеспечение для космического аппарата, самолета, машины; и многое другое. Поверьте, кто-кто, а программисты не скучают — для них всегда есть работа, которая требует и знаний, и навыков, и творческого подхода к решению. К тому же, у каждого человека свой спектр интересов. Кто-то программирование считает скучным вследствие своего гиперактивного способа жизни, а кто-то просто поддается влиянию когнитивного искажения, прислушиваясь к собственному ложному суждению, обусловленному субъективными предубеждениями и стереотипами, социальными, моральными и эмоциональными причинами, то есть, вырабатывает свое отношение к программированию на основе искаженной информации.   Миф 7. Программисты всё пишут с нуля Современные сложные программы состоят из сотен тысяч строк кода. Если бы программисты писали всё с нуля, то на разработку одной такой программы уходило бы очень много времени, особенно, если говорить про игры — там и вовсе приходилось бы для каждого нового экземпляра и движок свой создавать, и физику свою писать и делать много других лишних движений. А это и время, и деньги, и лишние нервы. Поэтому в среде программистов принято не заниматься разработкой “велосипедов”, а использовать проверенные наработки. Разработчики часто применяют сторонние библиотеки, а также код, который был написан ими самими либо другими кодерами для других проектов. Это существенно упрощает и ускоряет создание проектов любой сложности и любого объема.   Миф 8. Чтобы устроиться на работу в качестве программиста, необходимо очень долго учиться В каждом человеке это утверждение находит различное отображение. Кто-то может освоить ЯП и необходимые технологии за месяц. Кому-то на это потребуется пол года. Некоторые и за год не управятся. Все зависит от вашего желания и стремления изучать ЯП, а также от времени, выделяемого вами на теорию и практику. Поставьте перед собой четкую цель и не сворачивайте с выбранного пути. Максимально быстрого обучения можно достичь, выбрав хорошие курсы, разбавляя их большим количеством самостоятельной практики.    Миф 9. После курсов у вас сразу высокая ЗП Один из самых распространенных мифов, который делает программистов в глазах других, незнакомых с данной сферой занятости людей, буквально миллионерами. Мол, “вот мой знакомый недавно листовки раздавал, потом походил на курсы 2 месяца и теперь деньги лопатой гребет”. На самом деле все не так. Те, кто только окончил курсы по освоению той или иной IT-специальности, по своему уровню знаний и умений могут претендовать на должность разработчика-джуниора (младший разработчик, Junior Developer). Конечно, все зависит от выбранного направления и конкретного места работы, однако джуниоры не срывают куш и первое время имеют довольно невысокую зарплату, которая не всегда доходит до пятизначной отметки (если говорить об украинских гривнах). Приблизительно на третий год работы можно говорить о действительно хорошей заработной плате. Так что запомните: высокая ЗП — даже в IT — результат не курсов, а усердной и ответственной работы.     Миф 10. “Выучи язык программирования… за 1 час!” Миф касается различных видео уроков на YouTube, которые пестрят подобным названием и тем самым обманывают вас. Ни один язык программирования не учится за час. Большое количество опытных программистов утверждают: сколько лет они программируют, столько они изучают ЯП. Языки взаимодействия с электронно-вычислительными устройствами настолько же компактны и многогранны, как и те, которыми мы пользуемся в повседневности. Таким образом, во время изучения ЯП вы осваиваете основной синтаксис языка и то, как с ним работать. Затем во время профессиональной деятельности вы углубляетесь в язык и открываете для себя новые техники кодинга и решения различных задач. Но даже процесс овладения языком (синтаксис + основы работы с ним) — небыстрый процесс. У опытного программиста изучение нового ЯП может занять несколько дней. У новичка могут уйти месяцы — все зависит только от вас. Но на всевозможные “Выучи язык… за 1 час!” и подобные вещи не ведитесь; такие видео ролики создают иллюзию того, что вы знаете ЯП, в то время, как на самом деле вы толком ничего и не умеете.   Миф 11. Нельзя освоить программирование самостоятельно Можно. Просто на это уйдет больше времени, чем на обучение при помощи специализированных курсов. Причины тому очень просты: отсутствие ментора, который бы мог направлять вас в нужное русло, давать советы и отвечать на вопросы; отсутствие предельно четкого понимания о знаниях и умениях, которыми необходимо обладать, чтобы в будущем занять соответствующую должность; отсутствие четкой программы обучения, которая покроет весь необходимый профильный материал; отсутствие стимула и достаточной мотивации, которые обычно присутствуют в коллективной среде (тренер, другие учащиеся, домашние задания и т. д.). Главная проблема самостоятельного обучения в силе воли, которая зачастую быстро испаряется и в итоге изучение ЯП сводится к нулю. А программирование вещь серьезная — на недельку-другую все забросил и вот ты уже ничего не помнишь. Так что самостоятельно обучаться программированию можно, главное — запастись упорством, терпением, силой воли и мощной мотивацией, которая должна постоянно подпитываться.   Миф 12. Программисты разбираются во всём, что связано с техникой Как вы поняли из вступления статьи, это тоже миф, причем один из самых распространенных. Разработчик мобильных приложений специализируется на создании программ под мобильные устройства. Он знает соответствующие ЯП и смежные технологии, которые позволяют ему выполнять свою работу качественно и без лишних затрат времени, однако, с какой стати этот специалист должен уметь чинить телевизоры и устанавливать Windows? Или, например, человек увлекается программированием микроконтроллеров. Почему он должен уметь создавать веб-сайты, если это абсолютно другая отрасль в IT? Вы же не требуете от педиатра вылечить вам зуб, а от стоматолога — избавить вас от кашля? Хотя и тот и тот специалист — врач. Каждый является специалистом в своей области и не следует это забывать. Сюда же относится и миф о хакерах, согласно которому программисты приравниваются к людям этого рода деятельности. Опять-таки, сторонники данной теории слишком плохо знают IT-сферу, поэтому все равняют под одну гребенку. То, что человек разбирается в определенном ЯП и смежных технологиях не делает его хакером. Хакерство — это специфический род деятельности, который предусматривает достаточно глубокие знания компьютерных сетей, операционных систем, социальной инженерии, криптографии и множества других IT-ответвлений. Если хотите узнать больше подробностей, не пожалейте своего времени — совершите поиск по специализированным ресурсам и тогда сможете расставить все точки над “i“ — кто кем является и какой спектр знаний-умений какому IT-специалисту свойственен.     Миф 13. Программирование — мужское занятие Безусловно, мужчин в программировании больше, чем женщин. По данным исследования Stack Overflow Developer Survey 2020, женщин среди разработчиков 8%. В Украине процент женщин в IT в 2020 году достиг уровня 25%, согласно исследованиям DOU.ua. Однако, это связано, скорее, с определенными социальными и психологическими явлениями. Дело в том, что женщины по своей природе более “социальны”, чем представители мужского пола. Соответственно, они чаще выбирают те сферы занятости, которые предусматривают общение и социум. В то же время парни и мужчины увлечены преимущественно техническими науками, поскольку достаточно распространенная среди них интровертивность позволяет посвятить необходимое количество времени цифрам, формулам и вычислениям. Плюс детская любовь к конструкторам, машинам, компьютерным играм и всему, что связано с техникой, с экспериментами. Ну и стереотипы, привитые обществом — куда же без них. Однако, это ни в коем случае не означает, что женщинам путь в программирование заказан. С каждым годом все больше и больше представительниц прекрасного пола покоряют IT в различных его секторах. Не ведитесь на предубеждения — программирование абсолютно открыто для всех полов, народов и возрастов.    Миф 14. Существует самый-самый лучший языка программирования Очень часто в интернете можно наткнутся на неутихающие дискуссии касательно того, какой ЯП лучше. Однако “лучшего” не существует. ЯП подбирается под задачу, а не задачи под ЯП. Если вы хотите максимально быстро развернуть свой сайт, лучше обратить внимание на Python и фреймворк Django. Хотите самостоятельно запрограммировать, допустим, сигнализацию с инфракрасным датчиком? Выбирайте C/C++ либо низкоуровневый Assembler. Те же С/С++ подойдут под разработку тяжеловесных игр, а для более простых идеальным выбором будет среда разработки Unity вместе с языком C#. FrontEnd разработка немыслима без языков верстки HTML & CSS, а также языка программирования JavaScript. Определитесь с тем, какая сфера разработки вам интересна и тогда выбирайте тот язык, который вам по душе.    Миф 15. Разработчики компьютерных игр — самые богатые и счастливые люди в IT Казалось бы: ты посвящаешь себя тому, о чем мечтал, наверное, каждый ребенок девяностых и нулевых — компьютерным играм. Ну что может быть прекраснее этого? Воплощаешь в жизнь все свои детские задумки: создаешь героев, работаешь над их характерами, занимаешься реализацией собственного геймплея, придумываешь уникальные квесты, сюжет не хуже “Игры престолов”, открытый и насыщенный игровой мир… Да вот только одна проблема — это так не работает; на деле все получается совсем иначе. Чтобы стать разработчиком игр, необходимо ими “гореть”, причем “гореть” так, чтобы ни время, ни вода, ни песок, ни отсутствие кислорода не смогли потушить ваше пламя. Во-первых, богатство гейм девелоперов преувеличено. Если игра “выстреливает”, либо вы работаете на плюс-минус солидную студию, то тогда можно говорить о деньгах. Однако, приличное количество разработчиков занимаются инди-играми, то есть, разрабатывают игры без финансирования крупных компаний (в одиночку, либо небольшими группами энтузиастов). Естественно, пока вы работаете над своим продуктом, единственным источником внешних доходов могут быть лишь пожертвования (донаты) от потенциальной аудитории, которая заинтересована в вашем творении. Также, важно знать, что разрабатывать игры и играть в них — две абсолютно разные вещи. Игростроение — сам по себе трудоемкий и комплексный процесс, который сильно отличается от того, что мы себе воображали в детстве.   Подробнее о пути гейм-мейкеров вы можете прочесть в нашей статье “Как стать разработчиком игр”. В ней мы постарались собрать максимальное количество информации с отечественных и зарубежных информационных ресурсов, чтобы подать вам все самое вкусное в одном компактном виде.      Миф 16. Начинающим айтишникам устроится на работу невозможно Действительно, если брать на рассмотрение популярные направления в IT, то конкуренция достаточно большая. И это на фоне растущих с каждым годом требований от работодателей. Однако, это не означает, что IT-отрасль закрыла свои двери перед новичками. Как раз таки наоборот. Сегодня функционирует множество программ стажировок от известных компаний, занимающихся созданием программного обеспечения. Например, EPAM, GlobalLogic, SoftServe и другие открывают вакантные места для тех, кто хорошо знает предметную область, но не имеет опыта работы. Конечно, необходимо будет пройти тестирование и/или собеседование, однако, это уже упрощает процесс внедрения в рабочую среду желанной IT-секции.      Миф 17. Пойду в ВУЗ, там меня научат программированию В ВУЗе не обучают программированию в соответствии с теми требованиями и ожиданиями, которые предъявляют к соискателям IT компании. Хоть вам и будут преподавать алгоритмы и различные ЯП, но нагрузка в вузе будет настолько объемной и пёстрой, что вы физически не сможете нормально научиться программировать. Все равно вы будете вынуждены самостоятельно учить/доучивать тот или иной язык. Если бы вы поступали на факультет, допустим, прикладной математики, вы бы туда шли с сильными знаниями по математике, правда? Так же само и с айтишными факультетами: если вы туда идете, у вас УЖЕ должен быть опыт программирования на любом ЯП. Иначе вам будет очень тяжело и мучительно больно.   Миф 18. Программирование имеет возрастные ограничения Языки программирования, как и любые иностранные языки, вы можете начать изучать в любом возрасте. Возрастные рамки отсутствуют. Самое главное — это ваше желание учиться, развиваться и познавать. Как показывает практика, уже с 8-9 лет дети способны понимать основные концепции ЯП и успешно создавать собственные программы. Если говорить об относительно великовозрастных людях, с ними работает то же правило — никогда не поздно учиться и узнавать нечто новое. Более того, активная мозговая деятельность (как такая, которая происходит в процессе программирования) является отличной профилактикой многих заболеваний мозга, связанных со старением. Так что программирование и юных развивает, и взрослых прокачивает + помогает держать в тонусе свои мысли. Однако, при трудоустройстве возрастные ограничения могут иметь место. Это зависит от политики компании, которая ищет специалиста.   Миф 19. Программист — вымирающая профессия: роботы заменят этих специалистов Очень распространенное мнение, имеющее право на жизнь. С одной стороны, все верно: программ становится все больше и больше, а значит, потребность в программистах должна потихоньку отпадать (ведь скоро будет нечего программировать!); при этом активно развивается искусственный интеллект, способный перенимать определенные функции человека, включая написание кода, на себя. Поговорим о первом тезисе. Вроде бы все логично, но есть одно НО. Рассмотренная выше мысль будет абсолютно верна в том случае, когда мы говорим об информационных технологиях, как об области, которая находится в некоем вакууме, причем вакуум этот ограничен, то есть, имеет свой “потолок”, выше которого не прыгнешь. Наш же мир не является ограниченным, по крайней мере, человечество еще не смогло определить его грани. Да, человеческие возможности упираются в определенные физические ограничения (невозможно поднять руками или ногами самолет, самостоятельно прыгнуть на высоту 5 метров, проглотить целиком кокос и т. д.), однако в нашем мозгу пока что не было замечено четких ограничений. Более того, с его помощью мы научились обходить естественные физические преграды: придумали и реализовали специальный транспорт, который может перевозить тяжелые объекты; изобрели джамперы, джетпаки (реактивные ранцы) для совершения высоких прыжков и полетов в воздух на относительно небольшие высоты; специальные предметы для разделывания экзотических фруктов и т. п. Пока что ученые не смогли выжать максимум из нашего мозга и разглядеть границы нашего сознания. Если сложить вместе безграничность наших мыслей и безграничность мира, можно прийти к выводу, что любая сфера нашей жизни поддается совершенствованию и всегда есть, куда дальше двигаться. Все области нашей жизнедеятельности неразрывно связаны между собой, хотим мы того или нет. Особенно сфера IT — сейчас она находит свое отображение везде: музыка; киноиндустрия; компьютерные игры; банковская сфера; транспортная инфраструктура; сфера безопасности (физическая и кибербезопасность); СМИ; медицина; аграрная отрасль; все, что связано с космическими разработками; научные исследования любых направлений; сфера образования... Так можно продолжать, пока не будут перечислены все отрасли человеческой деятельности. Давайте обратимся к сухим фактам и посмотрим на то, как “умерли” некоторые профессии в результате их совершенствования: человечество уже научилось создавать искусственные фрукты и овощи, но фермеры никуда не пропали; более того — некоторые страны имеют острую нехватку профессионалов в аграрном деле; существуют дистанционно управляемые боевые машины, дроны и другие приспособления для ведения боевых действий, но никто не говорит о роспуске армейских подразделений; набор призывников и добровольцев продолжается и приветствуется во всех странах; в супермаркетах появились терминалы самообслуживания, однако продавцов никто не уволил; посмотрите вакансии на данную должность — их пруд пруди; пассажирские самолеты обустроены очень надежными и серьезными компьютерными системами, которые выполняют много работы за человека и даже имеют функцию автопилота, но никто не спешит увольнять самих пилотов; более того, в мире острая нехватка данных специалистов, а их зарплаты считаются одними из самых высоких в мире; такая же ситуация и с поездами — сегодня не надо кидать уголь в печь и разгонять поезд (как в XIX веке), но водители поездов никуда не испарились; беспилотные автомобили уже разъезжают по улицам некоторых городов, однако водители государственных и коммерческих предприятий тоже никуда не делись, вакансии пестрят предложениями для водителей; множество других примеров. Примерно та же ситуация и у программистов. Правда, сфера IT настолько многогранна, что профессии в результате развития данной области будут просто эволюционировать. Например, веб-мастер двухтысячных стал современным FullStack девелопером, а само направление сайтостроения поделилось на два лагеря — FrontEnd и BackEnd. На границе программирования и системного администрирования образовалась DevOps инженерия. IT-специальности будут попросту перерождаться и образовывать новый виток с новыми должностями. Для осознания системности нашего мира советуем прочесть книгу “Введение в системный анализ” (Ф. И. Перегудов, Ф. П. Тарасенко). Прекрасный труд, который очень хорошо демонстрирует взаимосвязанность всего, что нас окружает. Воспитывает системное мышление и заставляет смотреть на вещи более адекватно и трезво, находить логические связи между всевозможными событиями и процессами в нашем мире.  Поговорим о втором тезисе. Он касается искусственного интеллекта (ИИ). Сюда же добавим системы генерации кода, существующие в наше время. К примеру, взглянем на сервисы, которые позволяют создавать собственные сайты без знания IT технологий. Действительно, сегодня существуют подобные системы, использование которых исключает необходимость владения языками верстки и программирования, однако они предоставляют достаточно шаблонные решения. В них вы не сможете воплотить все свои задумки — это сможет сделать только живой специалист. Системы генерации кода хорошо справляются с типичными задачами, однако в реальных ситуациях, где не всегда всё просто и зачастую необходимо импровизировать, сохраняя при этом код “в чистоте”, они бессильны. Возвращаясь к разработчикам сайтов: верстальщики, FrontEnd и BackEnd разработчики не исчезли и спрос на них является одним из самых высоких среди направлений в IT. ИИ уже давно разрабатывается и ученые демонстрируют потрясающие результаты: системы, которые обыгрывают шахматных гроссмейстеров и легенд покера, робот София, системы по распознаванию образов и т. д. Однако, какого-то обвала рынка программистов не последовало, массовые увольнения специалистов замечены также не были. Все спокойно.  Посетите, например, такие ресурсы по поиску работы, как https://jobs.dou.ua/, grc.ua,  hh.ru — вакансий для сайтостроителей много, равно как и для других айтишных специальностей. Не похоже на упадок эпохи программирования. Несмотря на то, что сфера IT и без того находится на пике популярности, она испытывает дефицит рабочих кадров. Так что вы сможете прекрасно себя реализовывать в IT еще несколько десятилетий как минимум. Главное — следите за тенденциями в IT и ловите попутный ветер.   Итоги Большинство мифов, касающихся IT, рождены обыкновенным незнанием предметной области и изрядной долей ложных предубеждений. Сегодня мы постарались разрушить некоторую часть из них и показать вам, что программирование — не башня из слоновой кости, а вполне реальная и податливая сфера человеческой деятельности, в которой кипит жизнь и которая нуждается в пополнении своих рядов. Не бойтесь делать шаги навстречу программированию. Разрушайте стены незнаний и непониманий. Если вы в чем-то неуверенны,  интересуйтесь у знакомых-программистов, пишите на форумах, спрашивайте на стримах. Все зависит только от вас!   Желаем вам всевозможных успехов и профессиональных свершений! Оставайтесь с ITVDN!
ТОП 20 тестових завдань на інтерв'ю для Java розробника

Автор: Армен Маїлян

Напишіть програму на Java для перевертання рядка, змінивши розташування символів у рядку задом наперед без використання вбудованих в String функцій Напишіть програму на Java для перевороту послідовності символів у рядку без використання вбудованої в String функції reverse() Напишіть програму на Java для того, щоб поміняти місцями значення, що зберігаються у двох змінних за допомогою третьої змінної Напишіть програму на Java, щоб поміняти місцями значення, що зберігаються у двох змінних, без використання третьої змінної Напишіть програму Java для підрахунку кількості конкретних слів у рядку, використовуючи HashMap Напишіть Java-програму для ітерації об'єкта типу HashMap з використанням циклу while та покращеного циклу for Напишіть програму на Java, щоб дізнатися, чи є число простим, чи ні Напишіть Java-програму, щоб визначити, чи є рядок або число паліндромом, чи ні Написати програму на Java для обчислення серії чисел Фібоначчі Напишіть Java-програму для обходу ArrayList з використанням циклу for, while та покращеного циклу for Напишіть програму на Java, щоб продемонструвати явну перевірку умов очікування Напишіть Java-програму для демонстрації прокручування вгору / вниз Напишіть програму на Java, щоб відкрити усі посилання на gmail.com Напишіть код для Selenium, щоб перейти до попередньої вкладки Напишіть програму на Java, щоб знайти повторювані символи в рядку Напишіть Java-програму, щоб знайти друге за величиною число в масиві Напишіть Java-програму для перевірки, чи є введене число числом Армстронга Напишіть Java-програму для видалення всіх пробілів з рядка за допомогою replace() Напишіть Java-програму для видалення всіх пробілів з рядка без використання replace() Напишіть Java-програму для читання даних із таблиці Excel У цій статті ми наведемо досить багато прикладів програм з тих, що просять написати претендентів під час проходження інтерв'ю на вакансію Java розробника. Вказані тестові завдання ми наводимо з реальними прикладами коду, заданими в інтерв'ю як початківцям, так і досвідченим кандидатам. Сьогодні серед інтерв'юерів стало звичайною практикою давати тестові практичні завдання під час інтерв'ю, не фокусуючись лише на теоретичних питаннях. Такі завдання зазвичай задають на технічному етапі інтерв'ю Java розробника. Для того, щоб допомогти претендентам на відповідні вакансії пройти такі інтерв'ю, ми хочемо перерахувати кілька дуже важливих прикладів програм на Java разом з належним описом кожного. Крім того, ми також додаємо відповідні пояснення коду. Ці пояснення дадуть вам чітке уявлення, як працює кожна програма.   Найпопулярніші питання інтерв’ю Java-програмування. Q # 1) Напишіть програму на Java для перевертання рядка, змінивши розташування символів у рядку задом наперед без використання вбудованих в String функцій.   Відповідь: Для початку ініціалізуємо рядкову змінну st і використовуємо клас StringBuilder. Об'єкт класу StringBuilder strB буде надалі використовуватися для додавання значення, що зберігається в рядковій змінній st. Після цього ми використовуємо вбудовану в StringBuilder функцію reverse() і зберігаємо нову – обернений рядок в stB. Нарешті ми виводимо на екран stB. public class FirstTask{             public static void main(String[] args) {                         // ITVDN.com 1 із ТОП 20 тестових завдань на інтерв’ю для Java розробника                         String st = "Задача1";                         StringBuilder stB = new StringBuilder();                         stB.append(st);                         stB = stB.reverse();     // використовуємо StringBuilder для перевороту рядку                         System.out.println(stB);             } } На екрані отримаємо: 1ачадаЗ   Q # 2) Напишіть програму на Java для перевороту послідовності символів у рядку без використання вбудованої в String функції reverse().   Відповідь Спосіб 1: Є кілька способів, за допомогою яких ви можете перевернути ваш рядок, якщо вам дозволено використовувати інші вбудовані функції рядка. У цьому способі ми ініціалізуємо рядкову змінну з ім'ям st значенням заданого рядка. Потім ми конвертуємо цей рядок у масив символів за допомогою функції toCharArray(). Після цього ми використовуємо цикл for, щоб взяти всі символи у зворотному порядку і вивести їх так на екран по черзі. public class SecondTask {             public static void main(String[] args) {            //ITVDN.com 2 з ТОП 20 тестових завдань на інтерв’ю для Java розробника            String st = "Вчимося програмувати";                char symbols[] = st.toCharArray();  // конвертуємо рядок у масив символів, потім виводимо символи на екран у зворотному порядку            for(int x= symbols.length-1; x>=0; x--) {                         System.out.print(symbols [x]);            }       } } На екрані отримаємо: итавумаргорп ясомичВ Спосіб 2: Це ще один спосіб виконати завдання з переворотом послідовності символів у рядку. У цьому способі ви оголошуєте рядкову змінну st, а потім використовуєте клас Scanner, оголошуючи об'єкт scannerQ для роботи зі стандартним потоком введення даних. У цьому випадку програма набуде рядкового значення через командний рядок (при його виконанні). Далі ми використовували метод nextLine(), який прочитав наш рядок під час введення його через консоль з пробілами між словами рядка. Після цього ми використовували метод split() для поділу рядка на його підрядки (тут не вказується роздільник). Потім ми виводимо рядок у зворотному порядку, використовуючи цикл for. import java.util.Scanner; public class SecondTask {             public static void main(String[] args) {            // ITVDN.com 2 з ТОП 20 тестових завдань на інтерв’ю для Java розробника            String st;            Scanner scannerQ = new Scanner(System.in);            System.out.println("Введіть ваш рядок:");            st = scannerQ.nextLine();            String[] temp = st.split("");       //використовуємо метод split для виведення рядку в зворотньому порядку            for(int x= temp.length-1; x>=0; x--)            {                         System.out.print(temp [x] + "");            }                     } } На екрані отримаємо: Введіть ваш рядок: asfasdf aasdfasdfadsf fsdafdsafdsaa fdsafsa Спосіб 3: Це спосіб майже такий, як спосіб 2, але тут ми не використовуємо метод split(). Ми використовуємо клас Scanner та метод nextLine() для читання вхідного рядка. Потім ми оголосили цілочисельну змінну stringLength, присвоюючи їй значення довжини вхідного рядка. Після цього ми вивели рядок у зворотному порядку, використовуючи цикл for. Однак ми використовували метод charAt(index), який повертатиме символ за конкретним індексом. Після кожної ітерації символ буде додано до нового рядка для отримання перевернутого значення рядкової змінної. Потім ми виводимо змінну перевернутого рядка. import java.util.Scanner; public class SecondTask {             public static void main(String[] args) {            // ITVDN.com 2 з ТОП 20 тестових завдань на інтерв’ю для Java розробника            String mainString, reverseString = "";            System.out.println("Введіть рядок, щоб отримати перевернутий:");            Scanner scannerQ = new Scanner(System.in);            mainString = scannerQ.nextLine();            int stringLength = mainString.length();            for(int x= stringLength -1; x>=0; x--) {                        reverseString = reverseString + mainString.charAt(x);   //використовуємо вбудований метод charAt(), щоб перевернути рядок            }            System.out.println(reverseString);             } } На екрані отримаємо: Введіть рядок, щоб отримати перевернутий: Введений рядок кодяр йинедевВ   Q # 3) Напишіть програму на Java для того, щоб поміняти місцями значення, що зберігаються у двох змінних за допомогою третьої змінної   Відповідь: У цьому прикладі ми створюємо об'єкт класу Scanner для роботи зі стандартним потоком даних System.in. Ця програма прийматиме значення a та b через командний рядок. Ми використали nextInt(), який буде поміщати введені користувачем значення цілочисельних змінних в a і b. Також оголошуємо тимчасову змінну. Тепер логіка програми виглядає наступним чином: ми створюємо тимчасову або третю змінну з ім'ям temp, присвоюємо їй значення, що зберігається в змінній a, а потім присвоюємо значення b, і знову присвоюємо b значення temp. Таким чином, після виконання всіх операцій temp буде зберігати в собі значення a, a отримає значення b, а b матиме значення temp (яке дорівнює a).   import java.util.Scanner; public class ThirdTask {             public static void main(String[] args) {            // ITVDN.com 3 з ТОП 20 тестових задач на інтерв’ю для Java розробника            int a, b, temp;            System.out.println("Введіть значення a та b");            Scanner scannerQ = new Scanner(System.in);            a = scannerQ.nextInt();            b = scannerQ.nextInt();            System.out.println("До обміну значеннями " + a + b);            temp = a;            a = b;            b = temp;            System.out.println("Після обміну значеннями " + a + b);                          } }   На екрані отримаємо: Введіть значення a і b 23 45 До обміну значеннями 2345 Після обміну значеннями 4523   Q # 4) Напишіть програму на Java, щоб змінити місцями значення, що зберігаються у двох змінних, без використання третьої змінної.   Відповідь: Спочатку все буде так само, як і в наведеному вище прикладі. Лише подальша логіка зміниться. Тут ми спочатку присвоюємо змінній a значення a + b, что означає, що a буде тепер мати в собі значення як a, так і b. Потім ми присвоюємо змінній b значення a - b, що означає, що ми віднімаємо значення b із суми (a + b). Досі a все ще зберігає у собі суму початкових a і b. Але b має тепер значення первісного a. Нарешті, на третьому кроці ми присвоюємо a значення a - b, що означає, що ми віднімаємо значення змінної b (яка зараз вже має в собі значення a) із суми (a + b). В результаті цих дій ми змінили місцями значення, які зберігаються у змінних.   import java.util.Scanner; public class FourthTask {    public static void main(String args[])    {             int a, b;             System.out.println("Введіть потрібні значення a та b");             Scanner scannerQ = new Scanner(System.in);             a = scannerQ.nextInt();             b = scannerQ.nextInt();             System.out.println("До обміну значеннями\na = "+a+"\nb = "+b);             a = a + b;             b = a - b;             a = a - b;             System.out.println("Після обміну значеннями без проміжної змінної\na = "+a+"\nb = "+b);    } }   На екрані отримаємо: Введіть потрібні значення a та b 23 45 До обміну значеннями a = 23 b = 45 Після обміну значеннями без проміжної змінної a = 45 b = 23   Q # 5) Напишіть програму Java для підрахунку кількості конкретних слів у рядку, використовуючи HashMap.   Відповідь: Ця програма працює з класом-колекцією, в якій ми використовували HashMap для зберігання рядка. Насамперед, ми оголосили нашу рядкову змінну з іменем st. Потім ми використовували функцію split() з одиночним пробілом, щоб можна було розбити рядок на масив з декількох слів. Після цього ми створили екземпляр HashMap та цикл for. Всередині циклу for ми використовуємо оператор if else. Ми заходимо до кожного елементу масиву split та додаємо елементи цього масиву. Слова ми додаємо як ключі екземпляру HashMap. У якості значень HashMap ми будемо додавати те число, скільки разів при обході масиву слів нам це слово зустрілося. Якщо в наш екземпляр HashMap ми вже додали дане слово – при обході ми збільшимо значення, записане в HashMap відповідно до даного слова-ключа. Щоразу, коли слово буде зустрічатися повторно (ми бачимо, що слово в екземпляр HashMap ми вже додавали) – значення-лічильник збільшується на 1. Якщо таке слово раніше не зустрічалося – значення-лічильник встановлюється на 1. Зрештою, ми виводимо на екран HashMap. Зверніть увагу: ту ж програму можна використовувати і для підрахунку кількості символів у рядку. Все, що вам потрібно зробити, це видалити один пробіл (видалити пробіл, вказаний в методі split) і прописати String [] words = st.split (“”); import java.util.HashMap; public class FifthTask{             public static void main(String[] args) {            // ITVDN.com 5 з ТОП 20 тестових завдань на інтерв’ю для Java розробника            String st = "Current task posted for Java developers developers";            String[] words = st.split(" ");            HashMap<String,Integer> keyValue = new HashMap<String,Integer>();            for (int i=0; i<= words.length-1; i++) {                         if (keyValue.containsKey(words[i])) {                                     int counter = keyValue.get(words[i]);                                     keyValue.put(words[i], counter+1);                         }                         else {                                     keyValue.put(words[i], 1);                         }            }            System.out.println(keyValue);             } } На екрані отримаємо: {Java=1, task=1, developers=2, for=1, Current=1, posted=1}   Q # 6) Напишіть Java-програму для ітерації об'єкта типу HashMap з використанням циклу while та покращеного циклу for.   Відповідь: Тут ми спочатку вставили три елементи в змінну типу HashMap з ім'ям keyValue, використовуючи функцію put(). Розмір змінної keyValue можна одержати за допомогою методу size(). Після цього ми використовували цикл While для обходу keyValue, яка містить по одній парі ключ-значення для кожного елемента. Ключі та значення можуть бути отримані за допомогою методів getKey() та getValue(). Аналогічно ми використовуємо розширений цикл for, на елементах «qurentMe2» у HashMap. import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class SixthTask{             public static void main(String[] args) {            // ITVDN.com ТОП 20 тестових завдань на інтерв’ю для Java розробника            HashMap<Integer,String> keyValue = new HashMap<Integer,String>();            keyValue.put(1, "Hello");            keyValue.put(2, "World");            keyValue.put(3, "Have a nice day!");            System.out.println(keyValue.size());            System.out.println("Цикл While:");            Iterator iter = keyValue.entrySet().iterator();            while(iter.hasNext()) {                         Map.Entry qurentMe = (Map.Entry) iter.next();                         System.out.println("Ключ это " + qurentMe.getKey() + " Значення це " + qurentMe.getValue());            }            System.out.println("Цикл For:");            for(Map.Entry qurentMe2: keyValue.entrySet()) {                         System.out.println("Ключ це: " + qurentMe2.getKey() + " Значення це: " + qurentMe2.getValue());            }             } } На екрані отримаємо: 3 Цикл While: Ключ це 1 Значення це Hello Ключ це 2 Значення це World Ключ це 3 Значення це Have a nice day! Цикл For: Ключ це: 1 Значення це: Hello Ключ це: 2 Значення це: World Ключ це: 3 Значення це: Have a nice day!    Q # 7) Напишіть програму на Java, щоб дізнатися, чи є число простим, чи ні.   Відповідь: Ми оголосили дві цілочисельні змінні temp та number і використали клас Scanner з nextInt (оскільки у нас може бути на розгляді тільки ціле число). Оголошуємо логічну змінну numberIsPrime і встановлюємо її значення – true. Після цього ми використовуємо цикл for зі значенням змінної ітератора, що починається з 2. Кількість ітерацій, необхідне нам, дорівнюватиме половині введеного числа. Лічильник ітерацій збільшується на 1 після кожної ітерації. У змінну tempNumber ми поміщуватимемо залишок від поділу значення введеного числа на значення лічильника. Якщо залишок від поділу в одній з ітерацій дорівнюватиме 0, тоді numberIsPrime буде встановлений у false, введене число не буде простим, і ми виходимо з циклу. Якщо у всіх ітераціях ми отримуватимемо в temp деякі залишки від розподілу, відмінні від нуля – число буде простим. Ґрунтуючись на значенні numberIsPrime, ми приходимо до висновку, чи є наше число простим, чи ні. import java.util.Scanner; public class SeventhTask {             public static void main(String[] args) {            // ITVDN.com ТОП 20 тестових завдань на інтерв’ю для Java розробника            int temp, number;            boolean numberIsPrime = true;            Scanner scannerQ = new Scanner(System.in);            number = scannerQ.nextInt();            scannerQ.close();            for (int x = 2; x<= number /2; x++) {                         tempNumber = number %x;                                     if (tempNumber == 0) {                                     numberIsPrime = false;                                     break;                         }            }            if(numberIsPrime)                         System.out.println(number + " число є простим");                         else                                     System.out.println(number + " число не є простим");                      } } На екрані отримаємо: 27 27 число не є простим   Q # 8) Напишіть Java-програму, щоб визначити, чи є рядок або число паліндромом, чи ні.   Відповідь: Щоб перевірити, чи є число або рядок паліндромом, чи ні, ви можете використовувати будь-яку програму, що перевертає рядки, з описаних вище. Що вам потрібно зробити, то це додати один оператор if-else. Якщо вихідний рядок дорівнює перевернутому рядку, то число є паліндромом, інакше – ні. import java.util.Scanner; public class EighthTask{             public static void main (String[] args) {            // ITVDN.com ТОП 20 тестових завдань на інтерв’ю для Java розробника            String inputString, reversedString = "";            Scanner scannerQ = new Scanner(System.in);            int stringLength;            System.out.println("Введіть число або рядок");             inputString = scannerQ.nextLine();            stringLength = inputString.length();            for (int x = stringLength -1; x>=0; x--) {                         reversedString = reversedString + inputString.charAt(x);            }            System.out.println("перевернутое значение: " + reversedString);                         if(inputString.equals(reversedString))                         System.out.println("Введене значення є паліндромом");            else                         System.out.println("Введене значення не є паліндромом");                          } } На екрані отримаємо: Для рядка- Введіть число або рядок dfggg перевернуте значення: gggfd Введене значення не є паліндромом Для числа- Введіть число або рядок 777 перевернуте значення: 777 Введене значення є паліндромом   Q # 9) Написати програму Java для обчислення серії чисел Фібоначчі.   Відповідь: Ряд Фібоначчі - це така серія чисел, де після перших двох чисел кожне число, яке зустрічається, є сумою двох попередніх чисел. Приклад: 0,1,1,2,3,5,8,13,21 ……… У цій програмі ми знову використали клас Scanner з nextInt (описувалося вище). Спочатку ми вводимо (через командний рядок) деяке число, яку кількість чисел Фібоначчі ми повинні отримати. Ми оголосили цілочисленні змінні number, x, y та z, ініціалізували x та y нулем, а z – одиницею. Потім ми використовували цикл for для ітерації. Процес рішення в циклі виглядає так – ми присвоюємо x значення, рівне y (яке в першій ітерації дорівнює 0), потім y присвоюємо значення змінної z (рівне у першій ітерації 1). Потім змінної z привласнюємо значення, що дорівнює сумі значень x та y. import java.util.Scanner; public class NinthTask{             public static void main(String[] args) {            // ITVDN.com 9 з ТОП 20 тестових завдань на інтерв’ю для Java розробника            int number, x = 0, y=0, z =1;            Scanner scannerQ = new Scanner(System.in);            System.out.println("Введіть кількість значень");            number = scannerQ.nextInt();            System.out.println("Серія чисел Фібоначчі: ");            for (int i=0; i<= number; i++) {                         x = y;                         y = z;                         z = x+y;                         System.out.println(x + "");       // якщо ви хочете вивести в поточному рядку – використовуйте print()            }                          } } На екрані отримаємо: Введіть кількість значень 10 Серія чисел Фібоначчі: 0 1 1 2 3 5 8 13 21 34 55   Q # 10) Напишіть Java-програму для обходу ArrayList з використанням циклу for, while та покращеного циклу for.   Відповідь: У цій програмі ми додали три елементи до ArrayList і вивели його розмір. Потім ми використовуємо цикл While з ітератором. Щоразу, коли ітератор отримує наступний елемент, він буде відображати цей елемент, доки ми не досягнемо кінця списку. У нашому випадку це повторюватиметься тричі. Аналогічно ми зробили для покращеного циклу for, де ми створили об'єкт o для ArrayList з ім'ям testList. Потім вивели на екран значення об'єкта. Після цього ми створили цикл for, де ітератор i встановлено спочатку на індекс 0, а потім збільшується на 1 при кожній ітерації, поки не буде досягнута межа ArrayList. Нарешті, ми виводимо на екран кожен елемент, використовуючи метод get(index) для кожної ітерації циклу for. import java.util.*; public class arrayList {             public static void main(String[] args) {            // ITVDN.com 10 з ТОП 20 тестових завдань на інтерв’ю для Java розробника            ArrayList testList = new ArrayList();            testList.add("50");            testList.add("60");            testList.add("70");            System.out.println(testList.size());            System.out.println("Цикл While:");            Iterator iter = testList.iterator();            while(iter.hasNext()) {                         System.out.println(iter.next());            }            System.out.println("Покращений цикл For:");            for(Object o : testList) {                         System.out.println(o);             }            System.out.println("Цикл For:");            for(int i=0; i< testList.size(); i++) {                         System.out.println(testList.get(i));            } } } На екрані отримаємо: 3 Цикл While: 50 60 70 Покращений цикл For: 50 60 70 Цикл For: 50 60 70   Q # 11) Напишіть програму Java, щоб продемонструвати явну перевірку умов очікування.   Відповідь: У Selenium є два основні типи очікування – неявне (Implicit Wait) і явне (Explicit Wait). (Ми не розглядаємо явне (вільне) очікування у цьому прикладі). Неявне очікування – оголошується один раз у коді поза операцією пошуку та діє до зміни. Це очікування виконується незалежно від будь-якої умови і застосовується до всіх наступних операцій пошуку неявно. У наведеній нижче програмі ви можете бачити застосування такого очікування для Google Chrome. Ми використовували кілька вбудованих методів для встановлення властивості, максимізації вікна, навігації по URL та пошуку веб-елементів. WebDriverWait waitWD = new WebDriverWait(curentDriver, 20); WebElement secondElement = waitWD.until(ExpectedConditions.visibilityOfElementLocated(By.partialLinkText("Тестування програмного забезпечення - Вікіпедія"))); secondElement.click(); У наведеному вище фрагменті коду можна побачити, що ми створили об'єкт waitWD для WebDriverWait, а потім ми здійснили пошук WebElement з ім'ям secondElement. Умову встановлено таким чином, що веб-драйверу доведеться чекати, поки ми не побачимо посилання «Тестування програмного забезпечення – Вікіпедія» на веб-сторінці. Команда не виконається, якщо не знайде це посилання. Якщо посилання буде знайдено, веб-драйвер виконає клацання мишею за цим посиланням. package Codes; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; public class EleventhTask{             public static void main(String[] args) {                         // ITVDN.com 11 з ТОП 20 тестових завдань на інтерв’ю для Java розробника                         System.setProperty("webdriver.chrome.driver", "C:\\driver\\chromedriver.exe");                         ChromeOptions cOptions = new ChromeOptions();                         cOptions.addArguments("--disable-arguments");                         WebDriver curentDriver = new ChromeDriver();                         curentDriver.manage().window().maximize();                         curentDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);                         curentDriver.navigate().to("https://www.google.com.ua");                         WebElement curentElement = curentDriver.findElement(By.name("q"));                         curentElement.sendKeys("Testing");                         curentElement.submit();                         WebDriverWait waitWD = new WebDriverWait(curentDriver, 20);                      WebElement secondElement = waitWD.until(ExpectedConditions.visibilityOfElementLocated(By.partialLinkText("Тестування програмного забезпечення – Вікіпедія"))); secondElement.click(); } }   Q # 12) Напишіть програму на Java для демонстрації прокручування вгору/вниз.   Відповідь: Усі рядки кодів легко співвідносяться з кодом попереднього прикладу. У код цієї програми ми включили JavascriptExecutor jscript, який виконуватиме прокручування. На останньому рядку коду ми передаємо window.scrollBy(argument1, argument2). Якщо нам потрібно виконати прокручування вгору, тоді передаємо деяке значення в argument1, якщо нам потрібно прокрутити вниз – передаємо деяке значення в argument2.   package Codes; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebElement; public class TwelfthTask{             public static void main(String[] args) {                         // ITVDN.com 12 з ТОП 20 тестових завдань на інтерв’ю для Java розробника                         System.setProperty("webdriver.chrome.driver", "C:\\driver\\chromedriver.exe");                         WebDriver qurentDriver = new ChromeDriver();                         JavascriptExecutor jscript = (JavascriptExecutor) qurentDriver;                         qurentDriver.manage().window().maximize();                         qurentDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);                         qurentDriver.get("https://www.google.com.ua");                         WebElement qurentElement = qurentDriver.findElement(By.name("q"));                         qurentElement.sendKeys("SoftwareTestingHelp");                         qurentElement.sendKeys(Keys.ENTER);                         jscript.executeScript("window.scrollBy(0,900)"); } }   Q # 13) Напишіть програму на Java, щоб відкрити всі посилання на gmail.com.   Відповідь: Це типовий приклад застосування покращеного циклу for, який ми бачили у наших попередніх прикладах. Після того, як ви відкрили веб-сайт, такий як Gmail, використовуючи get() або navigate().to(), ви можете використовувати локатор tagName, щоб отримати всі посилання на веб-сайті, які мають однакові теги. У нас є покращений цикл for, в якому ми обходимо всі знайдені посилання за нашим тегом. Для кожного посилання типу WebElement у нашому листі посилань ми отримуємо самі посилання через getAttribute(«href») і тексти через getText(). package Codes; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; public class ThirteenthTask{             public static void main(String[] args) {             // ITVDN.com 13 з ТОП 20 тестових завдань на інтерв’ю для Java розробника             System.setProperty("webdriver.chrome.drive", "C:\\driver\\chromedriver.exe");             WebDriver curentDriver = new ChromeDriver();             curentDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);             curentDriver.manage().window().maximize();             curentDriver.get("https://www.gmail.com/");             java.util.List<WebElement> linkList = curentDriver.findElements(By.tagName("a"));             System.out.println(linkList.size());             for (WebElement thisLink: linkList) {             //виводимо на екран посилання http://google.com або https://www.gmail.com             System.out.println(qurentLink.getAttribute("href"));             //виводимо на екран текст посилання             System.out.println(qurentLink.getText()); } } } На екрані отримаємо: Starting ChromeDriver 2.38.551601 (edb21f07fc70e9027c746edd3201443e011a61ed) on port 16163 Only local connections are allowed. 3 https://support.google.com/accounts?hl=ru Довідка https://policies.google.com/privacy?gl=IN&hl=ru Політика конфіденційності https://policies.google.com/terms?gl=IN&hl=ru Умови використання   Q # 14) Напишіть код для Selenium, щоб перейти на попередню вкладку.   Відповідь: Ми використовуємо клас Robot. Цей приклад досить важливий, тому що, якщо ви знаєте поєднання клавіш, ви можете використовувати різну навігацію в браузері та його вкладках. Наприклад, якщо у вас у Chrome відкрито три вкладки, і ви хочете перейти на середню вкладку, то вам потрібно натиснути + 2 на клавіатурі. Те саме можна досягти за допомогою коду. Використовуйте наступний код (відразу після того, як ми побачимо створення екземпляру класу Robot). Ми використовували об'єкт qurentRobot класу Robot, з двома вбудованими методами keyPress(KeyEvent.VK_*) та keyRelease(KeyEvent.VK_*). package Codes; import java.awt.AWTException; import java.awt.Robot; import java.awt.event.KeyEvent; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; public class FourteenthTask{             public static void main(String[] args) throws AWTException {            // ITVDN.com 14 з ТОП 20 тестових завдань на інтерв’ю для Java розробника             System.setProperty("webdriver.chrome.driver", "C:\\driver\\chromedriver.exe");             WebDriver curentDriver = new ChromeDriver();             curentDriver.manage().window().maximize();             curentDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);             curentDriver.get("https://www.google.com");             WebElement firstElement = curentDriver.findElement(By.name("q"));             firstElement.sendKeys("software testing help");             firstElement.sendKeys(Keys.ENTER);             String str = Keys.chord(Keys.CONTROL,Keys.RETURN);              curentDriver.findElement(By.partialLinkText("Software Testing Help - A Must Visit Software Testing Portal")).sendKeys(str);             Robot qurentRobot = new Robot(); // Ініціалізуємо екземпляр класу Robot              qurentRobot.keyPress(KeyEvent.VK_CONTROL); // застосовуючи клас Robot ви легко можете отримати необхідний результат, якщо ви знаєте потрібні комбінації кнопок             qurentRobot.keyPress(KeyEvent.VK_2); // тут ми натискаємо ctrl+2              qurentRobot.keyRelease(KeyEvent.VK_CONTROL); // як тільки ми натиснемо та відпустимо ctrl+2, ми перейдемо на другу вкладку.             qurentRobot.keyRelease(KeyEvent.VK_2); //якщо ви хочете знову повернутися до першої вкладки, натисніть і відпустіть vk_1             } }   Q # 15) Напишіть програму на Java, щоб знайти повторювані символи в рядку.   Відповідь: У цій програмі ми створюємо рядкову змінну st та ініціалізуємо цілочисельний лічильник, починаючи з нуля. Потім ми створили масив символів для перетворення нашої рядкової змінної на цей масив. За допомогою двох циклів for ми проводимо порівняння символів із різними індексами. Якщо два символи послідовного індексу збігаються, цей символ буде виведений на екран і лічильник кількості символів, що збігаються, збільшиться на 1.  public class FifteenTask{             public static void main(String[] args) {                         // ITVDN.com 15 з ТОП 20 тестових завдань на інтерв’ю для Java розробника                         String st = new String("Hello");                         int counter = 0;                         char[] charsArray = st.toCharArray();                         System.out.println("Повторювані символи тут:");                         for (int i=0; i<st.length();i++) {                                     for(int j=i+1; j<st.length();j++) {                                                 if (charsArray [i] == charsArray [j]) {                                                            System.out.println(charsArray [j]);                                                            counter ++;                                                      break;                                                }                                     }                         }             } } На екрані отримаємо: Повторювані символи тут: l   Q # 16) Напишіть Java-програму, щоб знайти друге за величиною число в масиві.   Відповідь: У цій програмі ми ініціалізували масив із 10 випадковими елементами, з яких ми збираємося знайти друге за величиною число. Далі ми створили дві цілочисельні змінні, яким присвоюватимемо значення двох цілих чисел з масиву – найбільшого і другого за величиною. Обидві змінні спочатку набувають значення першого за індексом елемента масиву. Потім ми виводимо на екран усі елементи, використовуючи цикл for. Подальша логіка роботи програми полягає в тому, щоб використовувати цикл for для обходу масиву. При обході, якщо елемент масива з поточним індексом більше, ніж значення, що зберігається в змінній biggest, тоді змінній secondBiggest присвоюємо значення, що зберігається в biggest, а змінній biggest – нове найбільше значення відповідно до значення поточного елемента масиву. Знову ж таки, якщо елемент за поточним індексом більше, ніж secondBiggest, то привласність secondBiggest значення цього елементу. Це буде повторюватися для кожної ітерації і, зрештою, після завершення обходу масиву в циклі ви отримаєте елементи – найбільший і другий за величиною елементи масиву в змінних biggest і secondBiggest відповідно.   public class SixteenthTask { public static void main(String[] args)             {             // ITVDN.com 16 з ТОП 20 тестових завдань на інтерв’ю для Java розробника             int numbersArray[] = { 10, 15, 32, 100, 16, 11, 98, 36, 95, 33 };             int biggest= numbersArray[0];             int secondBiggest = numbersArray[0];             System.out.println("Отриманий масив: ");             for (int i = 0; i < numbersArray.length; i++)             {             System.out.print(numbersArray[i] + "\t");             }             for (int i = 0; i < numbersArray.length; i++)             {             if (numbersArray[i] > biggest)             {                         secondBiggest = biggest;                         biggest = numbersArray[i];             }             else if (numbersArray[i] > secondBiggest && numbersArray[i] != biggest)             {                         secondBiggest = numbersArray[i];             }             }             System.out.println("\nДруге за величиною число:" + secondBiggest);             } }   На екрані отримаємо: Отриманий масив: 10        15        32        100      16        11        98        36        95        33        Друге за величиною число: 98   Q # 17) Напишіть Java-програму для перевірки, чи введене число є числом Армстронга.   Відповідь: Насамперед, нам потрібно зрозуміти, що таке число Армстронга. Число Армстронга – це число, значення якого дорівнює сумі цифр, з яких воно складається, зведених у ступінь, що дорівнює кількості цифр у цьому числі. Як приклад – число 371: 371 = 3 * 3 * 3 + 7 * 7 * 7 + 1 * 1 * 1 = 27 + 343 + 1 = 371 Якщо у вас число чотиризначне: 8208 = 8 * 8 * 8 * 8 + 2 * 2 * 2 * 2 + 0 * 0 * 0 * 0 + 8 * 8 * 8 * 8 = 4096 + 16 + 0 + 4096 = 8208 Виконуючи рішення, спочатку ми оголошуємо цілочисленні змінні tempNumber, x і y. Ми ініціалізували змінну y значенням 0. Потім ми створюємо змінну qurentNumber і присвоюємо їй ціле значення, яке ми збираємося перевірити, чи є воно числом Армстронга (у нашому випадку це 371). Потім ми надали нашій змінній tempNumber те значення, яке зберігається в перевіреній змінній qurentNumber. Далі в циклі while ми змінній a привласнюємо залишок від ділення числа qurentNumber на 10 – і отримаємо число одиниць у початковому числі qurentNumber. Потім ми замінюємо значення змінної qurentNumber на результат діленого введеного числа на 10. Нашій змінній y, значення якої спочатку було встановлено як 0, присвоюється результат y + (x * x * x). Таким чином під час першої ітерації до y потрапить результат зведення в потрібний ступінь значення числа одиниць у початковому числі, при наступній ітерації до y до ступеня числа одиниць додасться результат зведення в ступінь числа десятків, і так далі по всіх розрядах до кінця числа qurentNumber з права на ліво. Нарешті, ми використовуємо оператор if-else для перевірки, чи буде отримане значення змінної y дорівнювати значення змінної tempNumber (у якій зберігається вихідне число). Якщо y = tempNumber, то загадане число є числом Армстронга, інакше – ні.   public class SeventeenthTask{  public static void main(String[] args)  {             // ITVDN.com 17 з ТОП 20 тестових завдань на інтерв’ю для Java розробника             int y=0, x, tempNumber;             int qurentNumber=371; //Дане число ми перевірятимемо на те, чи є воно числом Армстронга             tempNumber = qurentNumber;             while(qurentNumber >0)             {             x= qurentNumber %10;             qurentNumber = qurentNumber /10;              y=y+(x*x*x);                         }                         if(tempNumber ==y)                         System.out.println("Дане число є числом Армстронга");                          else                         System.out.println("Дане число не є числом Армстронга");     } } На екрані отримаємо: Дане число є числом Армстронга   Q # 18) Напишіть Java-програму для видалення всіх пробілів з рядка за допомогою replace().   Відповідь: Це проста програма, в якій ми маємо рядкову змінну st1. Інша рядкова змінна st2 ініціалізується за допомогою методу replaceAll, який є вбудованим методом для видалення n числа пробілів. У результаті ми виводимо на екран st2, яка вже не містить пробілів. public class EighteenthTask {             public static void main(String[] args)             {             // ITVDN.com 18 з ТОП 20 тестових завдань на інтерв’ю для Java розробника             String st1 = "Ми готуємось   до інтерв’ю   на вакансію     Java розробника";             //Використовуємо метод replaceAll()             String st2 = st1.replaceAll("\\s", "");             System.out.println(st2);             } } На екрані отримаємо: Миготуємосядоінтерв'юнавакансіюJavaрозробника   Q # 19) Напишіть Java-програму для видалення всіх пробілів з рядка без використання replace().   Відповідь: Це ще один підхід до видалення всіх пробілів. Знову ж таки, для початку у нас є одна рядкова змінна st1 з деяким значенням. Ми перетворюємо цей рядок на масив символів, використовуючи toCharArray(). Потім ми маємо один об'єкт StringBuffer strB, який буде використовуватися для додавання значення, що зберігається за індексом chars [i] після того, як ми додали цикл і одну умову if. Умову встановлено так, що елемент з індексом i масиву символів не повинен дорівнювати символу пробілу або табуляції. Зрештою, ми виводимо на екран наш об'єкт StringBuffer strB. public class NineteenthTask {             public static void main(String[] args)             {                         // ITVDN.com 19 з ТОП 20 тестових завдань на інтерв’ю для Java розробника             String st1 = " Ми готуємось  до інтерв’ю   на вакансію     Java розробника";             char[] charsArray = st1.toCharArray();             StringBuffer strB = new StringBuffer();             for (int i = 0; i < charsArray.length; i++)             {             if( (charsArray[i] != ' ') && (charsArray [i] != '\t') )             {                         strB.append(charsArray [i]);             }             }             System.out.println(strB);                      } } На екрані отримаємо: Миготуємосядоінтерв'юнавакансіюJavaрозробника   Q # 20) Напишіть Java-програму для читання даних із таблиці Excel.   Відповідь: Ці типи програм зазвичай використовують у рамках Selenium framework. Ми додали докладні коментарі для кожного кроку, щоб зробити програму більш зрозумілою. Логіка починається з того моменту, як ми завантажили лист, на якому зберігаються дані. Ми намагаємося імпортувати електронну пошту та пароль. Для цього ми виймаємо комірку за допомогою методів getRow() та getCell(). Припустимо, у нас є електронна пошта та паролі в 1-й та 2-й комірці. Далі ми встановлюємо тип комірки – рядкова. Після цього ми виконуємо звичайну операцію локатора веб-елемента (By.id), куди ми передали унікальні значення локатора, такі як "email" та "пароль", які ідентифікуватимуть ці елементи. Нарешті, ми надсилаємо ключі, використовуючи element.sendKeys, де cell.getStringCellValue() – це ключ. Ця операція поверне вам значення, збережене в комірках № 1 і 2 відповідно. @Test  public void ReadData() throws IOException  {            // Імпортуйте лист Excel з директорії web диску c.              //QurentSourceFile – це ім’я потрібного файлу excel              File sourceFile=new File("C:\\web\\QurentSourceFile.xls");              // На цьому кроці ми завантажуємо файл. Ми використовуємо FileInputStream для читання з // файлу Excel. Якщо ви хочете проводити запис у файл – // ви повинні використовувати FileOutputStream. Шлях до файлу передається // в якості аргументу FileInputStream              FileInputStream fileInput = new FileInputStream(sourceFile);                          // На цьому кроці ми завантажуємо робочу книгу Excel             // за допомогою HSSFWorkbook,             // в який ми передаємо fileInput в якості аргументу             HSSFWorkbook book = HSSFWorkbook(fileInput);             // На цьому кроці ми завантажуємо конкретний лист excel,             // на якому зберігаються дані.             qurentSheet= book.getSheetAt(0);              for(int i=1; i<= qurentSheet.getLastRowNum(); i++)              {             // Import data for Email.             qurentCell = qurentSheet.getRow(i).getCell(1);             qurentCell.setCellType(Cell.CELL_TYPE_STRING);                          driver.findElement(By.id("email")).sendKeys(qurenrCell.getStringCellValue());             // Імпортуємо дані з комірок з паролями             qurentCell = qurentSheet.getRow(i).getCell(2);             qurentCell.setCellType(Cell.CELL_TYPE_STRING);             driver.findElement(By.id("password")).sendKeys(qurenrCell.getStringCellValue());             }   } Резюме У цій статті ми розглянули найпоширеніші тестові завдання для розробників Java з прикладами коду. Ці завдання застосовуються на більшості технічних інтерв'ю Java розробників. Ми розглянули такі прийоми роботи з даними за допомогою Java, як базові маніпуляції з рядками, цілими числами та символами, використання Selenium, читання даних із файлу. Теперь у вас є достатньо інформації про те, як проходити технічний етап інтерв'ю на вакансію Java розробника. Звичайно, вам потрібні будуть інші навички. Вивчення напам'ять рішень 20 завдань може бути головним способом підготуватися до інтерв'ю. Вам слід мати гарний набір теоретичних знань та практичних навичок. З нашого боку портал ITVDN.com готовий запропонувати програму підготовки Java розробника, що включає відео курси як із Java, так і за супутніми технологіями. Також рекомендуємо вам ознайомитись із серією відео «Підготовка до співбесіди в IT компанії. Питання та відповіді. Хитрощі. Трюки» За матеріалами статті.
Введення в розробку програм під iOS. Частина 7

Автор: Volodymyr Bozhek

Здравствуйте, дорогие читатели. В этом уроке мы: выполним рефакторинг проекта “Warehouse” под “iOS”. Создадим удобную структуру расположения модулей в проекте. научимся пользоваться библиотекой “Alamofire”. научимся сохранять объекты в настройки телефона и извлекать их. реализуем функциональность для работы со всеми сервисами, созданными в данном уроке. Откройте проект “Warehouse” под iOS, который мы делали на протяжении всех уроков. Запросы на сервер можно отправлять синхронно и асинхронно. Основное требование Apple, чтобы приложение не зависало и большие операции выполнялись в фоновом режиме. Представим ситуацию: у нас мобильный интернет “GPRS EDGE”, скорость соединения около 54 кб/сек. Если отправлять запрос на получение данных на сервер синхронно, мы блокируем работу приложения и пользователь вынужден ждать. Наша задача - дать пользователю выбор, ждать или нет. Поэтому лучше всего отправлять такой запрос асинхронно. На сегодняшний день существует такая библиотека “Alamofire”, где собраны лучшие практики асинхронного программирования и все оптимизировано за нас. Откройте браузер и перейдите по адресу: “https://github.com/Alamofire/Alamofire”. На сайте нажмите кнопку “Clone of download” и в появившемся окне нажмите “Download Zip”. Когда скачается архив, распакуйте его. Выделите файл “Alamofire.xcodeproj” и папку “Source” и скопируйте их в папку проекта “Warehouse”. Перейдите в проект “Warehouse”. В панели навигации выполните контекстное меню по папке “Warehouse” и в контекстном меню выберите “Add files to 'Warehouse'...”. В открывшемся диалоговом окне выбора файлов  выберите файл “Alamofire.xcodeproj”. Выполните в меню “Product -> Build”, чтобы собрать проект. Затем выделите в панели навигации папку “Warehouse”, в области содержимого откроются свойства проекта. Откройте вкладку “General”, пролистайте область содержимого в самый низ. Установите свойство “Embedded binaries”, нажмите плюсик. В появившемся диалоговом окне, выберите “Alamofire.Framework.iOS” и нажмите кнопку “Add”. Результат должен получиться таким. Выполните в меню “Product -> Build”, чтобы собрать проект. Итак, что мы только что сделали. Мы подключили исходники библиотеки “Alamofire” в проект “Warehouse”. Можно было это сделать и отдельным проектом, но так проще для восприятия. Затем мы подключили сборку “Alamofire.framework.iOS” в приложение “Warehouse”  для возможности обращения к классам данной библиотеки из нашего проекта. Теперь нам надо создать модели данных, в которые мы будем сохранять JSON объекты, полученные с сервера. Также необходимо предусмотреть удобство сохранения и извлечения данных, поскольку запросы будут асинхронными и просто вернуть нужный экземпляр из метода будет проблематично. Именно поэтому мы поступим следующим образом. Отправляем запрос на сервер асинхронно. В метод отправки  добавляем callback метод, который вызовется  после того, как модель была успешно сохранена в настройки телефона. Ждем ответа. Когда ответ пришел, десериализуем объект JSON в нужную модель данных, объявленную в приложении. Сохраняем заполненную модель в настройки телефона. В контроллере, из которого был отправлен запрос, в callback методе  извлекаем модель из настроек телефона и инициализируем данными элементы управления. Создайте следующую структуру папок в панели навигации. В папку “Warehouse”  были добавлены папки “Controllers”, “Protocols”, “Models”, “Services”. В папку “Controllers”  были добавлены папки “Users”, “Registration”, “Authorization”, “Supplies”. В папке “Controllers”  будут храниться модули контроллеров. В папке “Protocols”  будут храниться модули протоколов. В папке “Models”  будут храниться модули моделей данных. В папке “Services”  будут храниться модули обращения к REST сервисам. Сейчас нам необходимо провести некоторую подготовку, перед тем как начать реализовывать приложение. Пока, давайте,  добавим нужные модули. Сам по себе добавленный модуль ничего не делает. Перетащите в папку “Controllers / Supplies”  модули “SuppliesViewController.swift”, “ProductViewController.swift”. Перетащите в папку “Controllers / Authorization”  модуль “ViewController.swift”. Добавьте в папку “Controllers / Registration”  модуль “RegistrationViewController.swift”. Добавьте в папку “Controllers / Supplies”  модуль “ImageCollectionViewController.swift”. Добавьте в папку “Controllers / Users”  модули “UsersViewController.swift”, “UserItemViewController.swift”. Добавьте в папку “Protocols”  модуль “SelectedImageProtocol.swift”. Добавьте в папку “Models”  модули “ProductModel.swift”, “UserModel.swift”. Добавьте в папку “Services”  модули “UserData.swift”, “ProductData.swift”, “Services.swift”, “AuthorizationService.swift”, “ProductService.swift”, “UserService.swift”. У вас должна получиться следующая структура. Как видите, проект стал больше. Он станет еще больше, как только мы заполним добавленные модули. Откройте модуль “Models / UserModel.swift”. Заполните его, как показано ниже. В этом модуле мы создаем модель пользователя, в которую будем десериализовывать JSON объект пользователя,  полученный от сервера. В классе “UserModel”  мы добавляем поля модели “_id”, “userName”, “userPwd”, “userDesc”, которые декларировали при объявлении схемы базы данных “Mongo DB” на сервере. На 9 строке  мы подключаем пространство имен “Foundation”. На 11 строке  мы объявляем класс с именем “UserModel”, который наследует класс “NSObject”, являющийся базовым классом для всех классов в iOS платформе. Наследуемся от протокола “NSCoding”, данный протокол необходимо реализовать, чтобы объект можно было сохранять в настройках телефона и извлекать оттуда. Рассмотрим протокол “NSCoding”. Протокол содержит метод “encode” и инициализатор. Экземпляр класса “NSCoder”  позволяет кодировать и раскодировать свойства класса, значения которых могут сохраняться в хранилище настроек телефона. В методе “encode”  данные извлекаются из свойств и кодируются в формат, нужный для сохранения в настройки телефона. В инициализаторе  данные извлекаются и раскодируются из настроек телефона, затем сохраняются в нужные свойства класса. Вот так это работает. Теперь вернемся и рассмотрим дальше модуль “UserModel.swift”. На 12 строке  мы объявляем поле “_id” типа “String” и инициализируем его значением по умолчанию, пустая строка. На 13 строке  мы объявляем поле “userName” типа “String” и инициализируем его значением по умолчанию, пустая строка. На 14 строке  мы объявляем поле “userPwd” типа “String” и инициализируем его значением по умолчанию, пустая строка. На 15 строке  мы объявляем поле “userDesc” типа “String” и инициализируем его значением по умолчанию, пустая строка. На 17 строке  мы переопределяем инициализатор по умолчанию для класса “NSObject”, тем самым мы говорим, что создание объекта без передачи аргументов в инициализатор будет возможно. На 18 строке  мы вызываем базовый инициализатор из класса “NSObject”. На 21 строке  мы объявляем параметризированный инициализатор. Данный инициализатор  инициализирует поля класса “_id”, “userName”, “userPwd”, “userDesc” значениями, переданными в аргументы инициализатора. На 31 строке  мы реализуем конструктор протокола “NSCoding”. Ключевое слово “required”  обозначает, что вызов этого инициализатора обязателен в первую очередь.   Ключевое слово “convenience”  гарантирует то, что после вызова этого инициализатора  будут вызваны остальные инициализаторы классов, связанных с этим классом по цепочке вверх. На 32 строке  мы раскодируем из настроек телефона  значение свойства “_id”  путем вызова на экземпляре “aDecoder” типа “NSCoder”  метода “decodeObject”, аргумент “forKey”  которого принимает название поля/свойства, которое было сохранено в настройки телефона. Этот метод возвращает значение “Any?”, т.е. неопределенный тип (аналог в C#  - это Object, в Visual Basic - это Variant). Нам необходимо это значение вручную привести к нужному типу поля. В настройках телефона содержится большой файл, который имеет древовидную  структуру словаря ключ и значение. Чтобы привести к нужному значению, мы используем конструкцию приведения к типу “as”. Причем, мы можем управлять этой конструкцией. Например, нам надо привести тип “Any?” к типу “String”. Для этого мы используем конструкцию “as!”. Если же нам надо привести к типу “String?” (nullable тип), тогда мы используем конструкцию “as?”. Зачем мы это делаем. Настройки телефона  разбиваются на разные файлы, для каждого приложения используется свой файл с настройками. Когда приложения устанавливаются на macOS или iOS платформу, они устанавливаются в виде папки и имеют тип “Bundle”. Apple довольно кардинально подошла к этому вопросу, она сделала так, что все настройки для каждого приложения хранятся внутри “Bundle” данного приложения. И когда приложение удаляется, удаляется “Bundle” со всеми настройками с диска операционной системы и не остается никаких следов после удаления. Чего не скажешь о таких платформах, как Windows и Android, которые засоряют все пространство на диске операционной системы вокруг папки, в которую было установлено приложение, и выше. И когда приложение удаляешь, есть риск, что после этого будет необходимо еще и переустановить операционную систему. Отчасти именно из-за этого подхода техника Apple  пользуется такой популярностью и их устройства выигрывают по отказоустойчивости программного обеспечения по сравнению с конкурентами. Если приложение обновляется, то файл настроек остается старый. Чтобы обновить его, надо выполнить запись в него, тогда старые конструкции удалятся, а новые добавятся.   Представим себе ситуацию, сейчас в нашей модели “UserModel”  всего 4 поля. Мы сохранили эту модель в файл настроек телефона. Отправили в магазин, пользователи скачали, установили приложение. Вышла новая версия приложения, в которой мы добавили новое поле в эту модель с именем “userRole” типа “String”. Разумеется, первая операция, которая будет выполнена как обычно - это запрос данных из настроек телефона, но для поля “userRole”  установлено значение “nil” (аналог в C# null) и произойдет ошибка и креш приложения, так как мы не обработали эту ситуацию, а пытаемся через метод “decodeObject” получить значение этого поля и еще и явно привести его к типу “String”  через, например, оператор “as!”. Но в поле “userRole” - значение “nil” и оно не приведется к типу “String” через конструкцию “as!”, но может привестись без ошибок к типу “String?”  через “as?”. Надеюсь, я прояснил понятно, зачем нужна данная проверка. Продолжим. На 32 строке мы проверяем, доступно ли нам значение поля “_id”. Чтобы проверить, равно ли возвращаемое значение “nil”, можно было бы использовать такую конструкцию: “aDecoder.decodeObject(..) == nil”, но такая конструкция не слишком информативна. Поэтому мы используем конструкцию “(aDecoder.decodeObject(..) as? String) == nil”.       Далее, если данная конструкция возвращает значение “true”, тогда мы через тернарный оператор  присваиваем  константе “_id” значение по умолчанию пустая строка, иначе присваиваем реальное значение  поля “_id” из настроек телефона. С 33 по 35 строку  мы выполняем те же операции проверок для полей “userName”, “userPwd”, “userDesc”. На 36 строке  мы вызываем параметризированный конструктор и инициализируем его аргументы объявленными ранее константами. На 47 строке  объявлен вспомогательный метод “Populate”, который переносит данные из экземпляра “dictionary” типа “NSDictionary”  в поля класса “UserModel”. Этот метод мы будем использовать, когда будем создавать запросы к серверу и получать ответы.   В ответе содержится словарь типа “NSDictionary”, в котором находятся свойства с теми же именами, что и поля нашего класса. С 48 по 51 строку мы инициализируем поля класса “UserModel”  значениями из экземпляра “dictionary” c теми же проверками, что мы рассматривали выше. На 53 строке объявлен вспомогательный метод “PopulateArray”, который переносит данные из экземпляра “array” типа “NSArray” в массив объектов типа “UserModel”. Этот метод мы будем использовать, когда в ответе от сервера  придет массив JSON объектов типа “User”, чтобы сконвертировать массив типа “[NSDictionary]” в массив типа “[UserModel]”. На 55 строке  мы объявляем пустой массив типа “[UserModel]” c именем “result”. На 56 строке  мы выполняем цикл “foreach” по элементам массива “array”. На 58 строке  мы создаем новый экземпляр типа “UserModel” с именем “newItem”. На 59 строке  мы проверяем, содержит ли элемент массива  значение “nil”. На 60 строке  мы вызываем на экземпляре “newItem”  метод “Populate”, который перенесет данные из словаря типа “NSDictionary”  в поля экземпляра “newItem”. На 62 строке  мы обращаемся к экземпляру “result” и вызываем у него метод “append”, чтобы добавить новый элемент в массив, и добавляем проинициализированный выше экземпляр “newItem”. На 64 строке  мы возвращаем сконвертированный массив типа “[UserModel]” из метода “PopulateArray”. Откройте модуль “Models / ProductModel.swift”, заполните его в соответствии с содержимым ниже. В этом модуле мы создаем модель пользователя, в которую будем десериализовывать JSON объект пользователя,  полученный от сервера. В классе “UserModel”  мы добавляем поля модели “_id”, “userName”, “userPwd”, “userDesc”, которые декларировали при объявлении схемы базы данных “Mongo DB” на сервере. На 9 строке  мы подключаем пространство имен “Foundation”. На 11 строке  мы объявляем класс с именем “UserModel”, который наследует класс “NSObject”, являющийся базовым классом для всех классов в iOS платформе. Наследуемся от протокола “NSCoding”, данный протокол необходимо реализовать, чтобы объект можно было сохранять в настройках телефона и извлекать оттуда. Рассмотрим протокол “NSCoding”. Данный модуль не нуждается в объяснении, поскольку он по образу и подобию такой же, как и модуль “UserModel.swift”, с разницей лишь в том, что он построен на модели “Product” и содержит соответствующие поля.       Итак, модели данных мы создали, теперь мы сможем с уверенностью сохранять результаты ответа от сервера в нормальном виде и потом использовать их при инициализации элементов управления в соответствующих представлениях :) Теперь приступаем к реализации классов для отправки запросов на сервер и сохранения/загрузки полученных данных в настройки телефона. Откройте модуль “Services / Services.swift”, заполните его в соответствии с содержимым ниже. На 11 строке  объявлен класс с именем “Services”. Данный класс будет содержать вспомогательные свойства и методы, которые мы будем часто использовать при работе с ответом от сервера. На 12 строке  объявлено статическое свойство “host” типа “String” и мы ограничили его функциональность только одним аксессором доступа “get”. Т.е. значение свойства получить можно, но изменить нельзя. В данном свойстве содержится адрес, по которому доступен сервер. В прошлом уроке, когда мы делали сервер, мы использовали адрес “http://localhost:3000” , внутри приложения клиента имеется свой “localhost”, именно поэтому мы используем явный IP адрес “127.0.0.1”, чтобы запрос шел именно на сервер, а не внутрь приложения. На 18 строке  объявлен статический метод “ejectJsonArray”, который принимает аргумент “data” типа “NSData?” и возвращает массив типа “NSArray?”. Данный метод конвертирует экземпляр класса “NSData” в экземпляр класса “NSArray”. В экземпляре “data” будет содержаться массив JSON объектов, полученных от сервера. На 19 строке  объявлена переменная “json” типа “NSArray?” и инициализировано значение по умолчанию “nil”. На 20 строке  мы используем конструкцию “do .. try .. catch” (аналог в C# - “try .. catch”). Символ “_” в блоке “catch” на месте аргумента используется потому, что мы не будем использовать этот аргумент в блоке “catch”. В случае возникновения исключения мы не будем завершать аварийно приложение, а просто вернем значение “nil” по умолчанию, которое будет говорить о том, что конвертация не удалась, поскольку в NSData  не содержится JSON объект. Аналог JSON объекта в Swift - это класс “NSDictionary”. На 21 строке  мы правым операндом обращаемся к классу “JSONSerialization” и вызываем от его экземпляра статический метод “jsonObject”, который первым аргументом принимает данные типа “Data” для конвертации, вторым аргументом принимает опции конвертации. Метод “jsonObject” возвращает экземпляр типа “Any”. Далее мы приводим это значение к нужному нам типу “NSArray?”, если приведение было проведено не успешно, будет возвращено значение “nil”. Результат конвертации присваивается объявленной выше переменной “json”. Обратите внимание на ключевое слово “try” перед конструкцией “JSONSerialization.jsonObject(..)”, использование этого ключевого слова является обязательным, так как метод “jsonObject” имеет в своей сигнатуре ключевое слово “throws”, это означает, что данный метод может генерировать исключения и их необходимо обрабатывать. На 23 строке в случае исключения вызванного методом “jsonObject”  возвращается значение “nil”. На 25 строке в случае успеха операции  возвращается экземпляр типа “NSArray?”. На 28 строке  объвлен метод “ejectJsonDictionary” с той же сигнатурой, что и метод “ejectJsonArray”, но с разницей в возвращаемом значении. В этом методе возвращается экземпляр типа “NSDictionary?”. Метод подразумевает, что в экземпляре “data” типа “NSData?” содержится единичный JSON объект и пытается его  сконвертировать в тип “NSDictionary” , являющийся аналогом JSON объектов в Swift.       Реализацию метода смысла описывать не вижу, она такая же, как и в методе “ejectJsonArray”. Реализуем сохранение моделей данных “UserModel” и “ProductModel” в настройки телефона. Откройте модуль “Services / UserData.swift”, заполните его в соответствии с содержимым ниже. Модуль большой, поэтому будем разбирать его, разбив на две части по функциональности. В первой его части  будут описаны методы сохранения / извлечения единичного экземпляра типа “UserModel” и экземпляра типа массив “[UserModel]”. Во второй его части  будут описаны вспомогательные методы  для обработчиков ошибок ответа от сервера и сохранения данных в настройки телефона. Данные методы были созданы для того, чтобы не копипастить один и тот же код много раз, а стандартизировать и сделать его повторно используемым. На 9 строке  подключено пространство имен “UIKit”, необходимое для классов “UserDefaults”, “NSKeyedArchiver”, “NSKeyedUnarchiver”. В пространстве имен уже содержится подключенное пространство имен “Foundation”, поэтому нет смысла его тоже  подключать для классов “NSArray”, “NSDictionary”, “NSData”. На 10 строке  подключено пространство имен “Alamofire”, необходимое для класса “DataResponse”. На 12 строке  объявлен класс с именем “UserData”. На 13 строке  объявлен метод “saveUserModel”, который принимает аргумент “userModel” типа “UserModel”. Метод будет сохранять поля модели “UserModel” в настройки телефона. На 14 строке  правым операндом мы обращаемся от экземпляра “UserDefaults” к его статическому свойству “standard”, это свойство является источником данных по отношению к файлу настроек телефона и содержит необходимые методы для сохранения / извлечения данных. На 15 строке  правым операндом мы обращаемся к экземпляру “NSKeyedArchiver” и вызываем статический метод “archivedData”. Этот метод принимает один аргумент “withRootObject” типа “Any” и возвращает экземпляр типа “Data”. Метод упаковывает экземпляр типа “UserModel” в экземпляр типа “Data” (аналог NSData) и возвращает его. На 16 строке  мы от экземпляра “userDefaults” вызываем метод “set”, который принимает два аргумента.  Первый аргумент “_” типа “Any?” принимает экземпляр, который необходимо сохранить в настройках телефона. Второй аргумент “forKey” типа “String” необходим, чтобы задать название ключа в словаре настроек  телефона. По этому ключу будет произведено сохранение экземпляра “UserModel”. На 17 строке  мы обращаемся к экземпляру “userDefaults”, вызываем от него метод “synchronize”. Данный метод выполняет сохранение экземпляра модели “UserModel” в настройки телефона (аналог в C#, например,  'using(StreamWriter sw = File.CreateText(“test.txt”)) { sw.Write(“some text”); sw.Flush(); }', из этого примера метод “Write” аналогичен методу “set”, а метод “Flush” аналогичен методу “synchronize”). На 20 строке  мы объявили статический метод “getUserModel”, который не принимает аргументов и возвращает экземпляр типа “UserModel”. В этом методе мы излекаем модель “UserModel” из файла настроек телефона по ключу, указанному в предыдущем методе при сохранении этой модели. На 21 строке  мы получаем экземпляр источника данных настроек телефона. На 22 строке  мы проверяем, если модель “UserModel” ранее не сохранялась в настройки телефона, тогда необходимо создать пустую модель по умолчанию. Вызываем на экземпляре “userDefaults” метод “object”, который принимает аргумент “forKey” типа “String” и возвращает значение типа “Any?”. В качестве аргумента мы передаем ключ, под которым сохраняется данная модель в настройках телефона. Если значение было найдено в словаре, будет возвращен экземпля , который надо будет привести у нужному типу. Если значение не было найдено, будет возвращено значение “nil”. На 23 строке  мы создаем пустой экземпляр типа “UserModel”. На 24 строке  мы возвращаем этот экземпляр из метода. На 26 строке  код будет выполнен при наличии записи по ключу в словаре. Правым операндом мы обращаемся к экземпляру “userDefaults”, вызываем метод “object” и передаем в аргумент “forKey”  ключ, по которому надо извлечь значение. Полученное значение приводим к типу “NSData”. На 27 строке  мы обращаемся к экземпляру “NSKeyedUnarchiver” и вызываем от него статический метод “unarchiveObject”, который принимает аргумент “with” типа “Data” и возвращает значение типа “Any”. Метод конвертирует экземпляр типа “Data” в экземпляр типа “Any”. Возращаемое значение метода мы явно приводим к типу “UserModel”. На 28 строке  мы возвращаем из метода полученный из словаря экземпляр типа “UserModel”. На 31 строке  объявлен метод “saveListOfUsersModel”, который принимает аргумент “listOfUsersModel” типа “[UserModel]” и ничего не возвращает. Метод сохраняет массив “[UserModel]” в файл настроек телефона. Описывать данный метод не имеет смысла, его работа аналогична методу “saveUserModel”. На 38 строке  объявлен метод “getListOfUsersModel”, который не принимает аргументов и возвращает экземпляр типа массив “[UserModel]”. Метод извлекает из настроек телефона массив типа “[UserModel]” по ключу, указанному в методе “saveListOfUsersModel”. Описывать данный метод не имеет смысла, его работа аналогична методу “getUserModel”. Откройте модуль “ProductData.swift”, заполните его в соответствии с содержимым ниже. В первой части описано сохранение / извлечение моделей типа “ProductModel”, “[ProductModel]” в настройки телефона. Описывать код не имеет смысла, его работа точно такая же, как и в модуле “UserData.swift”. Во второй части описаны вспомогательные методы для обработки запросов от сервера и сохранения данных. Описывать код не имеет смысла, его работа точно такая же, как и в модуле “UserData.swift”. Теперь, наконец то, мы можем реализовать первый класс для работы с сервисом авторизации пользователя и разобрать работу с библиотекой “Alamofire”. Откройте модуль “Services / AuthorizationService.swift”, заполните его в соответствии с содержимым ниже. На 12 строке  объявлен класс с именем “AuthorizationService”.             На 13 строке  объявлен метод “login”, который принимает три аргумента и ничего не возвращает.             Первый аргумент “userName” типа “String” -  это имя пользователя (логин).             Второй аргумент “userPwd” типа “String” -  это пароль пользователя.             Третий аргумент - это “callback” метод, который принимает аргумент типа “Bool” и ничего не возвращает.             Метод с такой сигнатурой, переданный в третий аргумент, будет вызван по завершению обработки ответа от сервера. В случае наличия ошибок  в аргумент этого метода будет передано значение “false”. В случае успешно проведенной операции - значение “true”.             Да, можно было сделать этот аргумент другим типом, например, отдельным классом ошибок, в который можно было сохранять подробно, что за ошибка произошла.             Но это учебный пример, он итак очень большой. Я решил не усложнять этим жизнь  ни себе, ни вам :)             На 14 строке  правым операндом мы вызываем метод “request” из библиотеки “Alamofire”.             Метод принимает 5 аргументов и возвращает значение типа “DataRequest”.             Данный метод используется для отправки HTTP/HTTPS запросов на сервер.             Первый аргумент “_” типа “URLConvertible” принимает адрес, по которому необходимо отправить запрос. Мы его инициализируем значением “\(Services.host)/auth”, которое после подстановки свойства “host”  будет выглядеть вот так: “http://127.0.0.1:3000/auth”.             Второй аргумент “method” типа “HTTPMethod” принимает HTTP глагол. Тип “HTTPMethod”  является перечислением и может принимать следующие значения. Мы инициализируем данный аргумент значением “.post” (это сокращенная запись, полная запись “HTTPMethod.post”)             Третий аргумент “parameters” типа “Parameters?”. Принимает словарь, ключ - значение, мы его заполняем теми же данными, что отправляли в прошлом уроке через утилиту “Postman”. Конкретно, мы передаем значение имени пользователя и его пароль.             Четвертый аргумент “encoding” типа “ParameterEncoding”. Этим параметром задается заголовок запроса “Content-Type”, т.е. указывается тип данных, который будет отправлен на сервер, сами данные задаются в третьем аргументе “parameters”. Мы инициализируем аргумент значением “JSONEncoding.default”, что аналогично записи “application/json”. Тип “ParameterEncoding” является протоколом и имеет следующие реализации себя в классах “URLEncoding”, “JSONEncoding”, “PropertyListEncoding”. Про эти классы вы можете почитать в официальной документации на сайте “Alamofire”.             Пятый аргумент “headers” типа “HTTPHeaders?” имеет значение по умолчанию “nil”, в нашем вызове метода он не используется. Данный аргумент задается, если вы желаете отправить в заголовках запроса на сервер какую- либо информацию, например, “cookie”. Если у вас сервер написан на Web API и вы используете для авторизации OWin , с настройкой надо использовать “cookie” как ключ авторизации пользователя. Тогда при отправке запросов вам будет необходимо заполнять этот аргумент. Пример его заполнения может выглядеть вот так: Этот пример взят из моего приложения “Smart Payment”,  написанного на Swift 2.2 c минимальной версией iOS 8.3  библиотекой “Alamofire” версии 2. Чтобы этот пример работал на Swift 3, надо заменить значение параметра “encoding” на “JSONEncoding.default”. Этот пример не относится к нашему приложению и его переписывать не нужно.             На 16 строке  мы вызываем от экземпляра “r” типа “DataRequest”  метод “responseJSON”. Этот метод выполняет запрос на сервер и содержит три аргумента.             Первый аргумент “queue” типа “DispatchQueue?”  по умолчанию содержит значение “nil”. Используется при переопределении потока выполнения запроса.             Второй аргумент “options” типа “JSONSerialization.ReadingOptions” по умолчанию содержит значение “.allowFragments”. Используется для задания опция отправки запроса.    Тип “ReadingOptions” является структурой и имеет такое объявление. Третий аргумент “completionHandler” типа делегат “@escaping (DataResponse) -> Void”. Данная сигнатура принимает один аргумент типа “DataResponse” и ничего не возвращает. В этом аргументе содержится ответ от сервера. Сам метод вызывается после запроса, когда сервер отправил ответ на клиент.             Обратите внимание, на 16 строке, когда мы вызываем метод “responseJSON”, у нас нет круглых скобок после метода, а идут сразу фигурные скобки, это называется “closure” подход. В фигурных скобках мы объявляем лямбда метод с сигнатурой, соответствующей третьему аргументу метода “responseJSON”.             Запись “response in” означает следующее: “response” - это аргумент лямбда метода, а само тело метода начинается после ключевого слова “in”. Аргумент “response” имеет тип “DataResponse”.             На 17 строке  мы проверяем, если ответ пришел с ошибкой, то это означает, что данных нет и пришло пустое значение типа “nil”. Мы обращаемся к экземпляру “response” и вызываем свойство “result” типа “Result” и от свойства “result” вызываем свойство “value” типа “Value?”. Если в свойстве “value” пришло пустое значение, значит запрос не был выполнен, возможно, по причине недоступности сервера или отсутствия подключения к интернету.             На 18 строке  мы вызываем “callback” метод “completion” со значением “false”.             На 21 строке, в случае если проблем с подключением к серверу не возникло, мы правым операндом вызываем от экземпляра “Services” метод “ejectJsonDictionary”, который ранее уже подробно рассматривали. В аргумент “data” мы передаем значение свойства “data”, вызванного от экземпляра “response”. Свойство “data” имеет тип “Data?”. Левому операнду “json” присваивается экземпляр “NSDictionary”, в котором содержится JSON объект пользователя, прошедшего авторизацию, который был отправлен сервером на клиент.             На 22 строке  мы проверяем, если пришел JSON объект с ошибкой, тогда возвращаем нужный флаг в “callback” методе “completion”. Помним, что в предыдущем уроке мы создавали JSON объект с ошибкой на сервере, в случае если пользователь ввел неверные данные авторизации,  JSON выглядел вот так '{ “Error”: “Authorization error”}'.             У словаря “json” есть возможность получить все ключи, для этого надо вызвать свойство “allKeys”, которое имеет тип “[Any]”. Но,  поскольку выполнить поиск строки в массиве объектов нельзя, мы оборачиваем массив объектов в массив типа “Array” и явно приводим его к нужному нам типу массива “[String]”. Мы это делаем, поскольку знаем наверняка, что ключи JSON объекта имеют тип “String”. Затем от полученного экземпляра типа “[String]”  мы вызываем метод “contains”, в аргумент которого передает название свойства JSON объекта ошибки, значение “Error”. Если такой JSON объект пришел в ответе, значит пользователь ввел неправильные логин или пароль, или ввел несуществующего пользователя.             На 23 строке  мы вызываем “callback” метод “completion” с аргументом “false”.             На 25 строке  мы создаем пустой экземпляр “userModel” типа “UserModel”.             На 26 строке  мы вызываем на экземпляре “userModel”  метод “Populate”  в аргумент “dictionary”, передаем экземпляр “json”. Метод “Populate”  перенесет данные из экземпляра “json” типа “NSDictionary” в поля экземпляра “userModel”.             На 27 строке  мы обращаемся к экземпляру “UserData” и вызываем статический метод “saveUserModel”, чтобы сохранить данные экземпляра “userModel” в настройки телефона. В аргумент “userModel”  мы передаем экземпляр “userModel”.             На 28 строке  мы вызываем “callback” метод “completion” и передаем в него результат операции “true”.             Позже в контроллере, где мы будем вызывать метод “login”, будет передан “callback” метод “completion”, объявленный в этом контроллере. Тем самым решается проблема ожидания ответа от сервера в контроллере, так как есть “callback” метод. Внутри этого метода мы проверим результат операции и затем обратимся к экземпляру “UserData” и вызовем метод “getUserModel”, который вернет нам экземпляр “UserModel”, с которым мы сможем работать на стороне контроллера.             Откройте модуль “Services / UserService.swift”, заполните его, как показано  ниже. На 12 строке  объявлен класс “UserService”.             На 13 строке  объявлен метод “get”, который принимает два аргумента и ничего не возвращает.             Первый аргумент “id” типа “String?”  принимает идентификатор пользователя “_id”. Если передать в аргумент значение “nil”, будет возвращен весь список пользователей, если передать конкретный идентификатор, будет возвращен конкретный пользователь.             Второй аргумент “completion” типа делегат “(Bool) -> Void”  используется для получения сигнала, что ответ был получен и основные операции были выполнены.             На 29 строке  объявлен метод “create”, который принимает 4 аргумента и ничего не возвращает. Метод отправляет запрос на создание пользователя на сервер.             Первые три аргумента “userName”, “userPwd”, “userDesc” имеют тип “String” и содержат данные пользователя. Идентификатор пользователя в операции создания не нужен. Так как идентификатор пользователю присваивается на стороне сервера и данный метод выполняет как раз эту операцию.             Четвертый аргумент “completion” типа делегат “(Bool) -> Void”  используется для получения сигнала, что ответ был получен и основные операции были выполнены.             На 37 строке  объявлен метод “update”, который принимает 5 аргументов и ничего не возвращает. Данный метод отправляет запрос на обновление данных пользователя на сервер.             Первые 4 аргумента “id”, “userName”, “userPwd”, “userDesc” имеют тип “String” и содержат данные пользователя.             Пятый аргумент “completion” типа делегат “(Bool) -> Void”  используется для получения сигнала, что ответ был получен и основные операции были выполнены.             На 45 строке  мы объявляем метод “delete”, который принимает два аргумента. Этот метод отправляет запрос на удаление пользователя на сервер.             Первый аргумент “id” типа “String?”  принимает идентификатор пользователя “_id”.             Второй аргумент “completion” типа делегат “(Bool) -> Void”, используется для получения сигнала, что ответ был получен и основные операции были выполнены.               Откройте модуль “Services / ProductService.swift”, заполните его, как показано ниже На 12 строке  объявлен класс “ProductService”.             На 13 строке  объявлен метод “get”, который принимает два аргумента и ничего не возвращает.             Первый аргумент “id” типа “String?”  принимает идентификатор товара “_id”. Если передать в аргумент значение “nil”, будет возвращен весь список товаров, если передать конкретный идентификатор, будет возвращен конкретный товар.             Второй аргумент “completion” типа делегат “(Bool) -> Void”  используется для получения сигнала, что ответ был получен и основные операции были выполнены.             На 29 строке  объявлен метод “create”, который принимает 4 аргумента и ничего не возвращает. Метод отправляет запрос на создание товара на сервер.             Первые три аргумента “productImage”, “productName”, “productDescription” имеют тип “String” и содержат данные товара. Идентификатор товара в операции создания не нужен. Так как идентификатор товару присваивается на стороне сервера и данный метод выполняет как раз эту операцию.             Четвертый аргумент “completion” типа делегат “(Bool) -> Void”  используется для получения сигнала, что ответ был получен и основные операции были выполнены.             На 37 строке  объявлен метод “update”, который принимает 5 аргументов и ничего не возвращает. Данный метод отправляет запрос на обновление данных товара на сервер.             Первые 4 аргумента “id”, “productImage”, “productName”, “productDescription” имеют тип “String” и содержат данные пользователя.             Пятый аргумент “completion” типа делегат “(Bool) -> Void”  используется для получения сигнала, что ответ был получен и основные операции были выполнены.             На 45 строке  мы объявляем метод “delete”, который принимает два аргумента. Этот метод отправляет запрос на удаление товара на сервер.             Первый аргумент “id” типа “String?”  принимает идентификатор товара “_id”.             Второй аргумент “completion” типа делегат “(Bool) -> Void”  используется для получения сигнала, что ответ был получен и основные операции были выполнены.             Заметьте, адреса запросов, используемых нами при отправке на сервер, совпадают с теми, что мы использовали в прошлом уроке в утилите “Postman”.             На этом урок завершен.             На следующем уроке мы продолжим разработку клиента, создадим контроллеры и представления для редактирования пользователей, подключим работу сервисов к странице входа в систему, создадим форму регистрации пользователя.
Як вибрати курси програмування?

Автор: Армен Маїлян

Что важно и с чего начать Критерии выбора курсов программирования Тренер Место проведения занятий График проведения занятий Размеры учебных групп Стоимость часа обучения/полного курса Общение с тренером Наличие и контроль выполнения домашних заданий Актуальность учебной программы История учебного центра Вывод   Что важно и с чего начать Если у вас есть высшее образование в области программной инженерии или компьютерных наук, то скорее всего вы знаете, какие курсы выбирать. Но если раньше вы не были связаны с IT, то выбор курсов программирования будет затруднителен. До наступления эпохи интернета главным источником знаний были ВУЗы и книги. Желающим научиться программировать приходилось тратить 5 лет на изучение целого комплекса наук, получать профессию «прикладного математика» либо другую, достаточно сложную профессию. Самообучение по книгам требовало высокой самоорганизации, умения выбрать правильные книги. Если учесть, что, что языки программирования и новейшие технологии разрабатываются преимущественно англоговорящими специалистами, доступ к самым новым знаниям сдерживался сроками, необходимыми для качественного перевода и издания книги на русском языке. Зачастую книги являлись некими справочниками – источниками информации для улучшения уже существующих навыков и знаний. Редкие книги позволяли полноценно провести человека, изучающего программирование, с нулевого уровня знаний, до уровня полноценного разработчика, который уже может устроится на работу по этой профессии. Популярной альтернативой для тех, кто хочет стать программистом, стали курсы программирования. Хорошие курсы помогают сформировать базовые знания и навыки по выбранной специальности, сориентировать в мире технологий и задать дальнейший вектор развития для начинающего специалиста. Критерии выбора курсов программирования Любой сложный выбор можно попытаться разбить на элементы, выделить важные части и сделать акцент именно на них. Так поступили и мы. Давайте рассмотрим вопрос выбора курсов программирования по пунктам. Тренер Как все мы понимаем, любые оффлайн курсы примерно на 90% времени состоят из общения студента с тренером. Именно такое общение является решающим для получения качественных навыков и знаний. Тренер читает лекцию, демонстрирует учебный материал, отвечает на возникшие у студентов вопросы, задает и проверяет домашние и классные задания. Для качественного учебного процесса этот тренер должен соответствовать неким критериям. Как нам правильно выбрать тренера по программированию? В первую очередь обратите внимание на уровень квалификации тренера. Очень важно, чтобы человек, обучающий других, сам был хорошо подкован и имел нужные знания. Если смотреть на курсы программирования, то таким критерием объективно может быть наличие общепризнанных сертификатов, профильное образование и, конечно же, опыт работы в реальных компаниях на реальных проектах, практический опыт решения проблемами с использованием новейших технологий. Обычно и сертификаты, и участие тренера в неких проектах, и образование можно вполне легко проверить. Вторым важным моментом в вопросе выбора тренера будет форма подачи материала, умение внятно и доступно рассказать, показать - любым способом донести учебный материал. Такие навыки тренера сложно проверить дистанционно. Именно поэтому многие компании, предоставляющие услуги обучения, дают возможность пройти бесплатно пробное занятие. Зачастую такого занятия будет достаточно, чтобы оценить подходит ли вам умение подать материал данного учителя или нет. Место проведения занятий Место получения вами знаний является важным фактором при выборе курсов программирования. Сам по себе этот пункт мы можем разделить на две части: территориальное расположение (локация) учебного центра; характеристика помещений и наполнения учебного центра. Если говорить о локации, то все мы понимаем, насколько удобнее приезжать в учебный центр, расположенный либо в центре города, либо возле серьезной транспортной развязки. Добираться после работы или учебы в другой конец города, тратя полтора-два часа только на проезд, воспринимается как вполне серьезное неудобство. Если учесть, что курсы будут длиться несколько месяцев, то вопрос расположения учебного центра становится вовсе не второстепенным. Другая часть пункта «Место» — это непосредственно наполнение учебного центра. Приходя учиться программировать, вы должны иметь возможность не только слышать тренера, но и видеть его действия с кодом и иметь возможность самим писать код, выполняя полученные задания. По этой причине важным будет вопрос оснащенности учебных аудиторий компьютерами с нужным установленным ПО, наличие нормального доступа в Интернет, иногда и возможность наблюдать за действиями тренера на большом экране телевизора или проектора, оснащенность учебного центра иными необходимым оборудованием. Если говорить о самих помещениях – большие аудитории для больших групп, маленькие аудитории - для малых. В зависимости от того, насколько индивидуальными будут ваши занятия, важно чтобы в учебном центре были подходящие помещения. Не стоит забывать и о комфорте. Занятия летом в помещении без кондиционера и вентиляции, а зимой без отопления,  сделают процесс учебы мучительным и сложным. График проведения занятий Работа или учеба - так или иначе у всех нас присутствует каждодневная загрузка. Для того, чтобы изучать что-то новое, чтобы получить нужные навыки или целую новую профессию – нам приходится изыскивать время. Поэтому важно чтобы наши возможности по наличию свободного времени мы могли реализовать в учебном центре. Иногда важно иметь возможность посещать курсы в выходной день – часто бывает так, что это единственная возможность выделить время для учебы.  Таким образом наличие групп обучения в удобное для вас время, это важный фактор при выборе учебного центра с нужными курсами программирования. Размеры учебных групп Все мы еще со школы помним, как удобно в больших классах думать какие-то свои отвлеченные мысли, заниматься какими-то своими делами, пока преподаватель задает вопросы вашему однокласснику. Но когда мы осознанно выбираем необходимость учиться, мы понимаем, что чем больше внимания мы уделим предмету учебы и чем больше преподаватель сможет уделить время нам - тем лучше для усвоения нами материала. Фактически лучше всего мы могли бы учиться, получая уроки индивидуально. Однако, в данном случае все упирается в стоимость учебы. Представьте ситуацию – имеется квалифицированный разработчик с полноценным опытом работы в различных программных проектах. Этот разработчик сдал в свое время необходимые экзамены и получил сертификат Microsoft/Oracle/Другая ТОП компания. Кроме того, этот программист владеет далеко не простым навыком – он умеет учить! Он может нормально передать знания, которыми владеет сам, объяснить, подсказать и т.д. Сколько стоит час времени такого разработчика? Как вы понимаете – не мало! А ведь есть еще дополнительные расходы – оплата подходящего места, доступ к интернету и др. Получая индивидуальные уроки, вы будете оплачивать час такого разработчика самостоятельно. Что вовсе не является таким уж рациональным подходом. Дело в том, что если образовательный процесс построен правильно, если правильно подобрана учебная информация, хорошо составлены лекции, студенту представлены нужные учебные материалы – студент ничего не потеряет, если будет слушать такую лекцию не индивидуально, а в компании с другими студентами. Далеко не всегда индивидуальные занятия дадут вам заметную разницу в усвоении материала. Скорее вам будет комфортнее получить знания в компании с другими студентами. Конечно же это должна быть не группа в 30+ человек. Важно выдержать баланс. Практика показывает, что группы в 8-10 человек достаточно сбалансированы между вопросом цены обучения и показателем качества получаемых знаний. Стоимость часа обучения/полного курса Мы понимаем, что время хорошего тренера будет стоить определенную сумму. Также мы понимаем, что аренда удобного помещения, с хорошим расположением и наличием нужного оборудования, тоже не будет бесплатной. Снизить цену на обучение нам поможет занятие в группе, когда общая стоимость курса будет разделена на всех студентов. Для себя вам нужно будет найти баланс между ценой и качеством услуг. Общение с тренером Посещая курсы, вы конечно же общаетесь с тренером. Как мы писали выше – около 90% времени, когда вы физически находитесь в учебном центре, проходит у вас в общении с вашим тренером. Вы слушаете лекцию, решаете заданные практические задания, задаете вопросы, получаете ответы.  Важным моментом во время обучения является возможность получения разъяснений за рамками стандартного учебного процесса. Ряд студентов во время учебы начинает выполнять свой учебный проект и нуждается в консультации и разъяснении вопросов вне учебной программы. Кому-то необходимо получить дополнительные задания и проконтролировать их выполнение. Кто-то недостаточно усидчиво работал во время предыдущих уроков и теперь нуждается в повторении и разъяснении уже пройденного ранее материала. Все эти вопросы могут быть разрешены если формат обучения в выбранном вами учебном центре позволяет получить такие консультации от тренера. Конечно же не бесплатно. Наличие и контроль выполнения домашних заданий Многие еще со школы не любят домашние задания. Выполнение домашних заданий и подготовка различных контрольных и курсовых проектов в вузе также мало радости приносят студентам. Но нельзя не заметить, что правильно организованный учебный процесс требует подкрепления полученных на уроке знаний. Именно механизмом подкрепления знаний и закрепления учебного материала выступает выполнение домашнего задания на курсах программирования. Каждому студенту необходимо не только услышать и увидеть различные синтаксические конструкции изучаемого языка программирования/фреймворка/библиотеки. Для получения устойчивого навыка студенту необходимо постоянно использовать эти конструкции в различных вариациях. Кроме того, при использовании таких конструкций студентом, обязательно будут появляться ошибки.  Именно выполнение правильно составленных заданий, а также поиск ошибок в своих решениях этих заданий и является той важной составляющей учебного процесса, которая позволит студенту закрепить полученные на уроках навыки. Стоит заметить, что важным будет не только сам факто того, что тренер эти задание задаёт, но и то, как он контролирует выполнение этих задания, есть ли у студента возможность получать разъяснения по домашнему заданию. Входит ли такая возможность в цену обучения или она осуществляется за отдельную доплату. Актуальность учебной программы IT сфера является одной из самых динамичных в мире. Постоянно происходит появление новых языков программирования, новых программных библиотек, новых технологических решений. Постоянно выходят дополнения и изменения уже существующих инструментов разработки. Постоянно меняются требования к соискателям на рынке труда. Студенту, желающему получить современную IT профессию, а также действующему специалисту, желающему улучшить имеющиеся навыки и изучить новые инструменты, важно получать знания о технологиях, актуальных именно на сегодняшний день, а также перспективных на день завтрашний. По этой причине, выбирая подходящие для себя курсы программирования, желательно обращать внимание на то, как часто пересматривается учебная программа курсов. Насколько детально она проработана. Важно понимать, насколько данная программа близка вашему текущему уровню знаний. Будете вы изучать технологии создания сайтов в сети Интернет или писать приложения для персональных компьютеров, важно - сможете ли вы начать изучать данный курс, будет ли вам понятен материал этого курса или вам лучше начинать с более базовых уроков. Есть ли такие базовые уроки в данном учебном центре? Также, выбирая курсы, важно понимать, как часто выходят дополнения к базовым материалам и насколько текущий курс учитывает последние изменения в современных инструментах разработки, насколько глубоко или широко представлены курсы по важным сопутствующим технологиям. Такое понимание, к сожалению, достаточно сложно для новичков в мире разработки программного обеспечения. Если бы студент имел понимание обо всех современных тенденциях и изменениях – возможно ему и не нужны были бы курсы. В таком случае стоит положиться на мнение более опытных коллег и поискать отзывы и рекомендации в сети Интернет. И тут мы подходим к последнему пункту нашего перечня из ответов на вопрос «как выбрать курсы программирования?». История учебного центра Мода на «войти в айти» все еще актуальна в постсоветских странах. В виду этого рынок услуг обучения не стоит на месте. Постоянно открываются новые учебные центры, постоянно закрываются те, которые не выдержали конкуренции. Не выдержали по разным причинам: не смогли предоставить нужное качество обучения, не смогли обеспечить рыночную цену за обучение, обучали не актуальным технологиям по старым материалам, а также по другим причинам. В таких условиях срок жизни учебного центра является важным показателем стабильности обучающего процесса и качества учебных материалов. Достаточная длительность существования учебного центра будет показателем как степени соответствия курсов актуальным технологиям в разработке ПО, так и своевременного внедрения новых технологий самого обучения.  Хорошим подспорьем при выборе учебного центра, в таком случае, будет наличие большого числа отзывов на соответствующих информационных площадках. Однако следует учитывать, что как положительные отзывы, так и отрицательные, могут оказаться маркетинговым ходом обучающих компаний. Положительные, могут оказаться выложены самими учебными центрами, а отрицательные – от недобросовестных конкурентов. Такая ситуация, к сожалению, далеко не нова на постсоветском рынке образования. Помочь разобраться в отзывах может понимание того, на какой площадке расположен отзыв, насколько анонимен автор отзыва и как реагирует администрация учебного центра, особенно если этот отзыв - негативен. Вывод Конечно, лучшим вариантом курсов программирования было бы индивидуальное обучение у высококвалифицированного и опытного специалиста по последним технологиям в удобное для вас время, с проверкой выполненных домашних заданий и возможностью получения бесплатных консультаций в любое время. И хотелось бы бесплатно! К сожалению, объективная реальность заставляет признать – такой комбинации не бывает. Однако и на сегодняшнем рынке образования можно найти курсы программирования с хорошим качеством обучения, подходящей ценой и устраивающими вас другими критериями выбора, упомянутыми в нашей статье. Если вы для себя решили получить профессию разработчика или, уже обладая этой профессией, решили изучить некую новую технологию, мы рекомендуем вам потратить немного времени и сопоставить предложенные в этой статье пункты с различными курсами, которые вы можете найти в сети. Мы уверены – с правильным подходом к выбору вы не разочаруетесь. Если вы уже знакомы с видео курсами ITVDN, вам могут понравиться очные и онлайн курсы нашего постоянного партнера – учебного центра CyberBionic Systematics. Более трети видео курсов, представленных в нашем каталоге, созданы тренерами этого учебного центра.
Асинхронне програмування на JavaScript

Автор: Дмитро Охріменко

План: 1. Різниця між синхронним та асинхронним кодом 2. Багатозадачність процеси й потоки, у чому різниця 3. Особливості багатозадачності в JavaScript 4. Асинхронні операції на практиці HTTP-запит як найпоширеніший кейс 5. Підходи до написання асинхронного коду: Promise    Async/Await Observable 6. Практичні поради Різниця між синхронним та асинхронним кодом Для початку давайте визначимо ці два терміни: Синхронний код - це код, який виконується послідовно, функція за функцією. Асинхронний код - код, який може виконуватися паралельно: наступна функція запускається, не чекаючи завершення попередньої. Щоб провести аналогію з реального життя, уявімо кухаря. Якщо кухар працює синхронно, то поки він не завершить приготування однієї страви, не переходить до наступної. Але це неефективно й призводить до втрати часу. Якщо ж кухар діє асинхронно, то поки м’ясо запікається в духовці, а на плиті закипає вода, він нарізає овочі. Тобто він один, але не стоїть без діла - виконує інші задачі, поки щось готується саме. Уявімо, що кухар - це процесор. А запікання м’яса в духовці - це завантаження файлу з мережі. Кухар може просто стояти й дивитись, як м’ясо готується. А може нарізати овочі, перевіряти, чи не з’явились нові замовлення, або скролити стрічку в соцмережі. Так само і з програмами: поки мережева карта завантажує файл, процесор не мусить чекати - він може малювати інтерфейс, оновлювати прогрес-бар чи виконувати обчислення у фоні. Але для цього потрібно правильно написати код - так, щоб він міг працювати асинхронно. Код який виконується синхронно ```js console.log("Початок"); console.log("Дія"); сonsole.log("Кінець"); ``` Результат: Початок Дія Кінець   Код який виконується асинхронно. і ``js console.log("Початок"); setTimeout(() => { // за допомогою setTimeout ми відкладаємо запуск коду на певний час   console.log("Дія через 2 секунди"); }, 2000); сonsole.log("Кінець"); ``` Результат: Початок Кінець Дія через 2 секунди Це не та багатозадачність, як у деяких інших мовах програмування. Тут не використовуються додаткові потоки, а все працює завдяки механізму подій. Але про це детальніше дал Багатозадачність: процеси й потоки, у чому різниця Багатозадачність в операційній системі - це можливість запускати та керувати кількома задачами одночасно. Наприклад, працювати в браузері, слухати музику, завантажувати файл і паралельно редагувати код у Visual Studio. На практиці процесор дуже швидко перемикається між усіма цими задачами, створюючи ілюзію одночасного виконання. Якщо процесор багатоядерний - деякі задачі справді можуть виконуватись паралельно. Багатозадачність тісно пов'язана з двома важливими поняттями - процесами та потоками. Процес (process) - це окремий екземпляр програми у пам'яті, який має власні ресурси: виділену область оперативної пам'яті, дескриптори файлів, змінні оточення тощо.  Потік (thread) - це одиниця виконання всередині процесу. Потоки одного процесу працюють незалежно, але мають спільний доступ до пам'яті та ресурсів процесу. Процеси дозволяють запускати різні програми одночасно - наприклад, Google Chrome, Visual Studio Code і т.д.  Потоки дають змогу виконувати кілька задач усередині однієї програми. Наприклад, у Visual Studio Code один потік відповідає за оновлення інтерфейсу, інший перевіряє помилки в коді, ще один формує підказки під час написання. Це, звісно, спрощений приклад - у реальності VS Code використовує ще й окремі процеси для розширень і мовних серверів. Операційна система керує як процесами, так і потоками. Вона розподіляє процесорний час між ними, ставить у чергу, може призупиняти виконання або відновлювати його за потреби. Давайте трохи адаптуємо наш приклад з кухарем із попереднього посту. Уявімо, що процес - це ресторан, а потік - це кухар. Ресторан має все необхідне для приготування їжі: кухонне приладдя, продукти, рецепти (це можна розглядати як пам’ять і доступ до інших ресурсів). Кухар читає рецепт і, використовуючи ресурси ресторану, готує страву - так само, як потік виконує інструкції нашої програми, використовуючи ресурси процесу. Якщо ресторан хоче готувати кілька страв одночасно, йому потрібно більше кухарів, які працюють паралельно на одній кухні. Аналогічно, якщо програма повинна виконувати кілька задач одночасно - завантажувати файли, обробляти введення, оновлювати інтерфейс - вона може використовувати кілька потоків. Коли ми створюємо програму і хочемо зробити її зручною для користувача, а також ефективною з точки зору використання ресурсів, які виділяє операційна система на процес, ми іноді починаємо використовувати потоки та прийоми багатопотокового програмування. Це велика окрема тема, і ми її зараз чіпати не будемо. Одна з причин - у JavaScript немає прямого доступу до потоків. Уточнення. Якщо ви хочете використовувати JavaScript і все ж таки працювати з потоками - у вас є Web Workers:  https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers  А якщо JavaScript виконується не в браузері (наприклад, у Node.js), тоді можна використовувати модуль `worker_threads`. Але варто розуміти, що це не частина стандарту мови, а можливість середовища виконання. Додаткові корисні ресурси по цій темі: https://www.youtube.com/@CoreDumpped - канал з короткими відео про те як працює комп'ютер. Modern Operating System by Andrew Tanenbaum - принцип побудови та роботи операційних систем (може бути викликом для новачка, але нормально як для технічної книжки) Особливості багатозадачності в JavaScript JavaScript працює в одному потоці - це означає, що в будь-який момент часу виконується лише один фрагмент коду. Увесь код, який ми пишемо, виконується у call stack: це структура, в яку потрапляють усі функції, що викликаються. Якщо одна з функцій виконується довго (наприклад, важке обчислення), усі інші задачі - включно з обробкою кліків, рендерингом чи відповідями від сервера - будуть чекати, поки call stack не звільниться. Щоб не блокувати цей єдиний потік, браузер надає асинхронні API (setTimeout, fetch, Web API). Коли ми викликаємо, скажімо, fetch(), у стек додається лише короткий виклик цієї функції. Власне мережевий запит виконується в окремому потоці, який створює браузер. Тобто, один потік виконує задачі які є у call stack, а інший потік чекає поки відповідь поверне сервер. Але асинхронна операція колись завершиться і треба механізм який віддасть нашому головному потоку результат роботи іншого потоку. Коли це стається колбек або проміс‑резолвер не додається одразу у call stack. Спершу він потрапляє до черги подій (task queue). За роботою черги стежить event loop. Його правило просте - поки стек порожній дістати першу задачу із черги і покласти у стек. Так ми досягаємо псевдобагатозадачності: основний потік виконує короткі шматки коду послідовно, а довгі операції «живуть» поза стеком. Коли довгі операції завершуються вони формують чергу задач, які треба виконати а event loop ці задачі закидає до стеку, коли call stack стає порожнім. Це максимально спрощене пояснення, і без візуалізації може здатися складним. Якщо хочете краще зрозуміти, дуже раджу подивитись відео Jake Archibald — "In The Loop" на YouTube (англійською).  https://www.youtube.com/watch?v=8aGhZQkoFbQ Або приходьте на мій курс JavaScript Поглиблений, де ми розбираємо це на практиці.  Також корисна стаття на MDN, де ці процеси описані докладніше. Асинхронні операції на практиці: HTTP-запит як найпоширеніший кейс Один з прикладів асинхронної операції - це запит на сервер через HTTP-протокол. Якщо організовувати запит через JavaScript у браузері без використання React, Angular або Vue.js, то це можна зробити за допомогою: fetch XMLHttpRequest Спеціалізована бібліотека, наприклад, Axios Ось так буде виглядати простий код написаний на fetch ```js fetch('https://jsonplaceholder.typicode.com/users')   .then(res => res.json())   .then(data => console.log(data)); ``` А так на axios (axios одразу повертає розпарсений JSON як response.data, на відміну від fetch, де потрібно викликати .json() вручну) ```js axios.get('https://jsonplaceholder.typicode.com/users')   .then(response => console.log(response.data)); ``` Якщо розглянути саме fetch то ось що відбулося під капотом: fetch створює HTTP запит вказавши HTTP метод, заголовки, тіло тощо Цей запит передається у вбудовану систему Web API - окрему від JavaScript середу, яка працює в іншому потоці. JavaScript не чекає відповіді - основний потік продовжує виконувати інший код fetch повертає Promise - об'єкт, що представляє асинхронну операцію, результат якої з’явиться пізніше Коли відповідь від сервера приходить, Web API кладе callback в чергу. Event Loop перевіряє, чи call stack порожній, і виконує цю мікрозадачу. Така поведінка дозволяє браузеру одночасно виконувати інші задачі, не чекаючи завершення запиту. Про використання асинхронного коду в JavaScript є [безкоштовний урок на YouTube](https://www.youtube.com/watch?v=cvR1EQ1R0EQ) Також більше про синтаксис Promise можна дізнатися в уроці [Асинхронний код. Promise](https://itvdn.com/ua/video/javascript-essential-ua/js-promise-ua) на ITVDN, а детальніше про варіанти організації такого коду буде написано далі. Підходи до написання асинхронного коду Складність роботи з асинхронним кодом полягає в тому, що обробка результату операції відбувається не відразу, а через певний час після її запуску. Ми ініціюємо асинхронну операцію й можемо виконувати інші завдання, але все одно маємо якось дізнатися про її завершення та обробити результат. Проблема в тому, що в цей момент програма вже виконує інші дії. Тому для обробки асинхронних операцій використовується push-модель взаємодії: отримувача даних (наш код) викликає провайдер даних - окремий механізм, який керує асинхронною операцією. По суті, розробнику потрібно відреагувати на подію завершення асинхронної операції. Для цього існує кілька підходів: callback-функція Promise async/await (синтаксичний цукор над Promise) Observables Використання функцій зворотнього виклику (callback) Почнемо з callback-функцій. Це найпростіший підхід, але він може призвести до заплутаного коду, особливо коли одна асинхронна операція запускає іншу, і так утворюється ланцюг. Уявімо, що маємо функцію downloadImage(url, callback), яка завантажує зображення асинхронно, не блокуючи основний потік. Перший параметр - це адреса зображення, яке потрібно завантажити, а другий - функція, яку буде викликано після завершення завантаження. При цьому саме зображення буде передане як параметр у callback. Приклад використання: ```js downloadImage(url1, image => document.body.append(image)) ``` На перший погляд усе просто. Але якщо потрібно завантажити кілька зображень послідовно, код стає менш зрозумілим: ```js downloadImage(url1, image => {             document.body.append(image);             downloadImage(url2, image => {                         document.body.append(image);                         downloadImage(url3, image => {                                     document.body.append(image);                         })             }) }); ``` Така вкладена структура швидко ускладнюється, особливо якщо замість одного рядка з DOM-змінами з’являється додаткова логіка. Подібний стиль називають "Pyramid of Doom", і його краще уникати. Один зі способів спростити обробку асинхронних викликів - це використання Promise. Використання Promise Promise - це об’єкт, який представляє асинхронну операцію. У перекладі з англійської promise означає «обіцянка». Можна уявити, що це обіцянка від браузера надати в майбутньому або результат операції, або помилку, пов’язану з її виконанням. Приклад використання: перепишемо попередню функцію downloadImage, щоб вона повертала Promise. ```js let promise = downloadImage(url1); promise.then(image => document.body.append(image)); ``` Тут ми все одно використовуємо callback-функцію, але передаємо її вже в метод .then() об’єкта promise. Це важливий момент: тепер асинхронна операція має об’єктне представлення, яке можна передавати як параметр у різні частини коду; можна будувати ланцюжки промісів, позбуваючись вкладеності, яка виникала з callback. Приклад: ```js downloadImage(url1)                          // отримуємо проміс .then(image => {                             // вказуємо що робити коли promise перейде в стан resolved             document.body.append(image);             return downloadImage(url2);                // виконуємо метод, який повертає promise }) .then(image => {                             // результат роботи попереднього промісу передається як значення             document.body.append(image);             return downloadImage(url3); }) .then(image => {             document.body.append(image); }); ``` Тепер код виглядає лінійним і набагато зручнішим для супроводу. У прикладах вище ми не розглядали, як саме створюється Promise, адже важливо зрозуміти мотивацію використання цих об’єктів. Тим більше, що більшість API браузера вже повертають готові проміси. Наприклад: ```js fetch('<https://jsonplaceholder.typicode.com/users>')   .then(res => res.json()); ``` Якщо хочете детальніше розібратися зі створенням Promise вручну - перегляньте документацію на MDN або мій відео урок на ITVDN. Async/await Супроводжувати синхронний код завжди простіше, ніж асинхронний. У 2012 році в мові C# з’явився синтаксичний цукор, який значно спростив роботу з асинхронними операціями: замість вкладених callback можна було використовувати послідовний синтаксис з новими ключовими словами async та await. Згодом цю концепцію перейняли й інші мови програмування, зокрема Python та JavaScript. В JavaScript підтримку async/await додали у 2017 році. Призначення ключових слів async - додається до функції та вказує, що вона завжди повертає Promise. await - використовується перед об’єктом-промісом, щоб "дочекатися" результату перед виконанням наступних рядків коду. Перепишемо попередній приклад із завантаженням зображень, використовуючи async/await: ```js let image = null;   image = await downloadImage(url1); document.body.append(image);   image = await downloadImage(url2); document.body.append(image);   image = await downloadImage(url3); document.body.append(image); ``` Тепер код виглядає як звичайний синхронний: немає вкладених callback, усе читається рядок за рядком. Можна подумати, що await "зупиняє" виконання, очікуючи на результат промісу. Насправді ж код не блокує основний потік - під капотом він перетворюється на машину станів, де кожен стан описує дію до або після await. Ще одна перевага async/await - знайомий синтаксис для обробки помилок: ```js try {             let image = null;               image = await downloadImage(url1);             document.body.append(image);               image = await downloadImage(url2);             document.body.append(image);               image = await downloadImage(url3);             document.body.append(image); } catch (ex) { // обробка помилки } ``` У результаті асинхронний код виглядає так само зрозуміло, як і синхронний, що значно спрощує його супровід. Observable Observable - це ще один підхід до організації асинхронного коду. Назва походить від однойменного патерна проєктування (Observer pattern), який описує створення об’єктів, за якими можна «спостерігати», отримуючи від них сповіщення. Тобто це реалізація подієвої моделі за допомогою ООП. У сучасному JavaScript ця ідея пішла далі й стала основою реактивного програмування та бібліотеки RxJS. Якщо Promise представляє одне майбутнє значення (успішне або помилкове), то Observable - це потік значень, які можуть з’являтися з часом. Можна уявити: Promise - це одна посилка, яку ви отримаєте в майбутньому; Observable - це підписка на журнал, нові випуски якого надходитимуть регулярно. Щоб створити Observable, використовують конструктор або готові оператори RxJS. Наприклад, функція downloadImages(urls) може завантажувати кілька картинок і відправляти їх «у потік» по мірі завантаження: ```js import { Observable } from 'rxjs';   function downloadImages(urls) {   return new Observable(subscriber => {     urls.forEach(url => {       downloadImage(url, image => {         subscriber.next(image); // надсилаємо картинку у потік       });     });     subscriber.complete(); // повідомляємо, що потік завершено   }); } ``` Щоб використати Observable, на нього треба підписатися за допомогою subscribe: ```js downloadImages([url1, url2, url3])   .subscribe({     next: image => document.body.append(image), // що робити з новим значенням     error: err => console.error(err),           // обробка помилок   }); ``` Переваги Observable працюють із потоком даних, а не з одним результатом; підтримують підключення операторів трансформації (фільтрація, мапінг, комбінування потоків); можна легко скасувати виконання (відписатися від потоку). Нижче приклад обробки даних через оператори. В RxJS оператори підключаються через метод pipe: ```js import { filter, map } from 'rxjs/operators'; downloadImages([url1, url2, url3])   .pipe(     filter(image => image.width > 100), // пропускаємо лише великі картинки     map(image => {       image.classList.add('highlight');       return image;     })   )   .subscribe({     next: image => document.body.append(image),     error: err => console.error(err),     complete: () => console.log('Готово')   }); ``` Таким чином, як і у випадку з Promise, можна будувати ланцюжки обробки. Але Observable значно гнучкіші: вони дозволяють працювати не лише з одним значенням, а з динамічною послідовністю даних у часі. Для глибшого занурення рекомендую офіційний гайд Observable на RxJS.dev. та відео уроки Observables. Частина 1, та Observables. Частина 2[1]  Практичні поради по работі за асинхроним кодом Не змішуйте підходи без потреби Якщо почали писати з async/await, не вставляйте всередину .then() без особливої причини. Це ускладнює читання. Обробляйте помилки Використовуйте try/catch для async/await або .catch() для Promise. У випадку Observable завжди додавайте обробку error у subscribe(). Скасовуйте непотрібні операції Для Observable використовуйте unsubscribe(), коли потік більше не потрібен. Для fetch можна застосувати AbortController, щоб зменшити навантаження й уникнути витоків пам’яті. Уникайте "Pyramid of Doom" Замість вкладених callback застосовуйте Promise, async/await або Observable. Використовуйте паралельне виконання Якщо операції незалежні, запускайте їх одночасно через Promise.all(). Ізолюйте логіку обробки Розділяйте завантаження даних та маніпуляції з DOM. Це спростить тестування й повторне використання коду. Логуйте стан і помилки Під час розробки виводьте у консоль ключові події асинхронних операцій, щоб відстежувати їх послідовність. Пам’ятайте про event loop Розуміння різниці між мікрозадачами й макрозадачами допоможе прогнозувати порядок виконання коду. Перевіряйте сумісність середовища Деякі API можуть бути відсутні у певних середовищах (наприклад, fetch у Node.js доступний лише починаючи з версії 18).
Notification success