Как стать автором
Обновить

Первый год в Rust — история любви

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров3.7K

Много лет назад я учился в Политехническом университете и уже думал о том, чем хочу заниматься, но не знал, чем именно. Поковырялся в html, css и js, написал несколько простых телеграм-ботов на питоне (с тех пор они канули в Лету), потом сделал то же самое на Java.

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

Но во время пандемии 2020 года я оказался в информационном поле Linux и с тех пор сильно вник в Linux. В этом году ради общности и системности, чтобы делать задачи, а не придумывать их, потому что та или иная ответственность, я искал «веб-разработку для начинающих» и нашел наставника. Сначала мы обсуждали варианты реактивного кодирования, но затем наставник спросил, что меня интересует, и я сказал, что в целом интересуюсь разработкой программного обеспечения, а мысли о ржавчине/++ отложил в долгий ящик. Итак, я начал писать Rust для проекта Retina в Norcivilian Labs.

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

Сначала мы работали с Nix и Linux. Для того, чтобы начать участвовать в проекте, нам нужно было всё настроить. Я установил NixOS, настроил его и зарегистрировался в нашем проекте на GitLab. Мы сразу же столкнулись с ошибками и добавили сопоставление с образцом в Nix-флейк для запуска оболочки кроссплатформенной разработки.

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

REST API уже реализован на серверах Retina, и наш интерфейсный инженер уже разработал первоначальный макет. Его историю можно прочитать здесь. Теперь мне нужно было создать правильные запросы в Rust. Я использовал crate reqwest. crate — это аналог библиотеки, точно так же, как используется например std vec в C++. Я создал запрос из сериализованной встроенной структуры данных хэш-карты в Rust. Я провел сериализацию, так как запрос принимает текст, я преобразовал структуру хэшмапа в строку. Потом я отправил этот запрос и получил обработанный ответ. Дальше я провел сериализацию, создал структуру для логина и с помощью метода json превратил ее в структуру, и функция вернула токен, как и требовала документация.

Задача была готова, я проверил ее, запустил приложение, убедился, что оно работает, записал состояние с помощью команды println!, которая вывела все в системный терминал. Поскольку Retina работает на Tauri и использует браузерный системный движок со встроенной клиентской консолью, я также записывал туда данные. Затем я удалил все логи, закоммитил и отправил мерж-реквест.

В этот момент я также начал читать «Программирование на Rust» Джима Бленди, действительно хорошую книгу. Книги очень плотные и дают знания, только это во многом достигается ценой времени.

Следующее задание, которое я взял, — это регистрация.

Эта задача была аналогичной, ее реализация была организована технически и организационно одинаково. Я создал функцию, которую вызываю из клиентской части с помощью команды вызова, так устроен Таури, и я должен передать данные в эту функцию. В клиентской части пользователь заполняет данные, из формы я передаю их на бэкенд и сразу десериализую эти данные в Rust. Я получил данные со стороны клиента, создал запрос по тому же запросу, провел сериализацию по тому же шаблону сопоставления, обработал ошибку и отправил POST-запрос, передав ему тело запроса. И тогда в ответ я получаю данные, состоящие всего из одного поля «ок», но мне еще нужно десериализовать это поле, обработать обработку ошибок и вернуть результат. На этом этапе была готова еще одна задача, я прописал команду Tauri в lib.rs, создал функцию, сделал GET-запрос через клиент блокировки reqwest, получил JSON, сделал обработку ошибок, взял string.status("ok"), залогинился и, таким образом, создали новые данные, чтобы пользователь мог войти в систему.

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

Далее был профиль выборки.

Я взял токен у клиента и получил данные профиля пользователя, чтобы, когда клиент нажимает на профиль, он видел данные о себе. История была та же самая: я переместил старый код JavaScript в браузер.js и создал фасад в api.js, который вместо этого будет вызывать новый код Rust. в Rust я создал функцию get_user_data, клиент отправил ей токен, функция получила токен, десериализовала его, создала хеш-карту. Я сверился с документацией и передал в тело запроса необходимые поля, включая токен и имя операции. Я получил ответ и структурировал его в нужную структуру. Здесь я уже вернул структуру в виде json, поэтому я возвращаю структуру, а Таури позаботится о сериализации, поэтому она поступает клиенту как json. Очередной PR был готов.

В Rust есть мем, что весь код состоит из развёрток, unwrap. Существует проверка, которая вызывает панику, если значение внутри скобок не соответствует действительности. Еще есть проверка, которая паникует, если внутренности не равны. Есть проверка, которая паникует, если у меня ошибка. В Rust для этого существует специальный тип результата, и некоторые методы возвращают результат, который я обрабатываю, используя сопоставление с образцом. В Result есть дженерик, я проверяю его с помощью ok err, вижу, что это такое, возвращаю только то, что мне нужно. Также есть ожидание, когда я также создаю панику, но когда выходит значение «err», ошибка того или иного рода, я вызываю панику и пишу сообщение внутри параметра ожидания.

Сначала я писал, можно сказать, в тестовом режиме, везде использовал unwraps — встроенный в Rust метод, который обрабатывает ошибки путём паники и закрытия приложения. Этот метод в большинстве случаев непригоден, поскольку мы не хотим, чтобы программа закрывалась, мы хотим, чтобы она их обрабатывала по аналогии с try catch.

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

Многие методы языка Rust возвращают результат или опцию. Разработчики Rust сделали это для того, чтобы когда я возвращаю тип, который не готов, я хочу получить строку, в ответ приходит строка, Rust возвращает вариант, который мне нужно расширить. поэтому это и называется unwrap - открыть, распаковать. Соответственно, вместо нашего итогового типа данных я меняю тип на Result и убираю развертку и то значение, которое я получил, тоже делаю опцию. Наше промежуточное значение — это не строка, а Result<string, string>. Я создаю промежуточную переменную, в которую записываю Результат, записываю конечную переменную, беру тег, инструкцию, тег как в других языках, например в языке Java есть такое понятие, как переключатель регистра, что То есть тег также является случаем переключения, когда я должен получить от него результат. Если все "ок", записываю в переменную, если приходит ошибка то не записываю ошибку в конечную переменную, конвертирую к нужному типу так как в расте строгая типизация, мне обязательно нужна строка, однако при в этот момент я пишу возврат и наша команда просто завершается на этом этапе. Преимущество здесь в том, что завершается не программа, а только команда, пользователь не увидит, что программа упала, он увидит ошибку внутри самой программы. Наконец, рефактор был готов.

Моя следующая задача — отправить картинку, потому что Retina устроена таким образом, что я отправляю изображение сетчатки на сервер, и оно передается ИИ. История та же, делаю запрос, который помимо токена принимает картинку и в ответ получаю данные, которые отправляю клиенту.

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

Я использую Linux для разработки, дома использую vim и bash. Прежде всего, мне нужно продолжать применять разные части Rust на практике, усложнять задачи, в идеале, лучше знать sql и Docker, ведь их обычно просят или дают как плюс.

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

Теги:
Хабы:
Всего голосов 11: ↑6 и ↓5+4
Комментарии4

Публикации

Истории

Работа

Rust разработчик
6 вакансий

Ближайшие события

22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
2 – 18 декабря
Yandex DataLens Festival 2024
МоскваОнлайн
11 – 13 декабря
Международная конференция по AI/ML «AI Journey»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань