Всем привет! Меня зовут Влад, я работаю дизайнером в компании SC.Soft. Проектирую сложные интерфейсы для телеком-индустрии. В этой статье я поделюсь опытом в проектировании загрузчика файлов. Расскажу о трудностях с которыми мы столкнулись, как можно было избежать проблем в проектировании и поделюсь лучшими практиками, которые мы выявили опытным и эмпирическим путём.
Разные загрузчики на всех продуктах
Приступая к новому компоненту, хочется сделать его универсальным — предусмотреть всевозможные варианты, чтобы переиспользовать его и не изобретать каждый раз велосипед.
Первым делом мы посмотрели загрузчики во всех наших продуктах, выявили что у них общего, определили достоинства и недостатки.

В некоторых продуктах мы просто не знаем, на сколько файл загрузился. Это связано с тем, что процедура проверки файлов в системе запускается раз в минуту, и если мы загрузили файл в начале этой проверки — то придётся ждать минуту, пока файл не проверится и не добавится в систему. В идеальном мире и при правильно спроектированной логике мы можем запустить процедуру добавления в систему сразу после загрузки файла. Так получилось реализовать на одном из наших новых продуктов. Но а если нет такой возможности вторгаться в логику уже работающих систем?
Нужно спроектировать понятный интерфейс для разных продуктов, на каждом этапе загрузки и добавления файла; пользователю должно быть понятно, на каком этапе находится файл.
Используйте drag & drop
Эта функциональность очень широко распространилась благодаря продуктам вроде яндекс диск, google drive, dropbox и прочим виртуальным хранилищам файлов. Поэтому большинство пользователей ожидают, что смогут перетаскивать файлы на страницу не только в популярных продуктах, но и в очень нишевых интерфейсах, которые используются для работы.
Я исследовал популярные загрузчики файлов и применил лучшие практики под интерфейсы компании.
1. Обычное состояние (Default)
Даём короткую инструкцию, что можно не только перетаскивать файл в целевую область, но и кликнуть на неё для загрузки файла. Также стоит указать ограничения по формату и размеру загружаемых файлов, если таковые есть.

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

2. Состояние наведения (Hovered)
Всегда давайте обратную связь на действия пользователя в интерфейсе, таким образом вы покажите, что элемент интерактивен и с ним можно взаимодействовать.

3. В движении
Когда мы перетащили файл в область для загрузки, то должны объяснить пользователю что происходит — меняем текст инструкции на «Добавить 1 файл», также помимо текстовой обратной связи — меняем и визуальную, — заливаем область взаимодействия цветом, как при ховере.

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

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


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

Наиболее быстрый и современный загрузчик может отображать прогресс загружаемых файлов.

В случае недопуска файла к загрузке пишем причину.

Иногда просто загрузки файла в систему недостаточно. Нужно отдельно подтвердить его добавление. Связано это с тем, что в загружаемом файле могут находиться строки, указанные в неправильном формате. Зачем грузить в систему битые данные?
Давайте обратную связь о составе файла: если есть некорректные данные, не загружайте их без дополнительного подтверждения.


Для высоконагруженных систем обработчик загрузки файлов реализуют таким образом, что он запускается раз в минуту: прогоняет все загруженные файлы и запускает процесс добавления записей из файла в систему. В новом продукте мы, конечно же, сделали запуск применения сразу после нажатия на кнопку «добавить».

После добавления записей уведомляем об успешной операции

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

Окно можно разернуть в полноэкранный режим и посмотреть детальную информацию о состоянии файла.

Модальное окно загрузки файла можно свернуть на любом этапе:
загрузка
проверка
добавление
оповещение (успех, ошибка)

Не дайте пользователю заблудиться
Загрузка файлов работает таким образом, что одновременно можно загрузить несколько файлов для разных страниц, и что в свёрнутом, что в развёрнутом состоянии непонятно, на какой странице и в какой список загружается файл.
Кажется, что самое лучшее решение — сделать отдельное место для просмотра всех загруженных файлов. Но на самом деле это не совсем так.
Есть системы, в которые мы грузим целые справочники, которые используются в ключевой логике работы приложения. Например, справочник стран, абонентов, базовых станций.

Если таких страниц много, то конечно сделать общую страницу менеджера загрузок — отличное решение.
Но также есть продукты, у которых всего несколько страниц, на которые можно загрузить файлы, например, списки IMSI и MSISDN.
Про IMSI и MSISDN
Оба этих номера являются важными элементами при работе с мобильной связью и используются для управления сетью и обеспечения безопасности передачи данных.
IMSI (International Mobile Subscriber Identity) — это уникальный идентификатор мобильного абонента.
MSISDN (Mobile Subscriber International Detach Number) — международный номер телефона.

Добавлять отдельное рабочее место во все системы — избыточно как для новых продуктов, которые мы обрекаем на лишние страницы, так и для уже запущенных в продакшн — нужно перепродумывать логику, делать большой рефакторинг.
Нам нужно найти более универсальное решение, которое бы не противоречило логике уже готовых продуктов, но улучшило опыт пользователей.
Возвращаемся к изначальному вопросу: куда загружается файл?
Решение этой проблемы нам подсказали несколько клиентов в опросах и один из базовых принципов проектирования. Нужно отвечать на вопрос пользователя «где я?». Показываем место: куда файл загружается. В какую таблицу, на какую страницу.
Дорабатываем хедер развёрнутого модального окна — добавляем подпись к окну загрузки.

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

Теперь однозначно можно идентифицировать, куда файл загружается и не запутаться в какую страницу идти за проверкой.
Не перекрывайте основной функционал
Столкнулись с проблемой: свёрнутые загрузчики скрывают пагинацию таблиц.

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

Ко всему прочему, большое количество загрузок может не поместиться в экран.
Эти проблемы натолкнули на то, чтобы пересмотреть отображение свёрнутых загрузок.
В итоге мы сделали свёрнутый загрузчик компактнее, объединили загрузки в один блок и добавили ещё один уровень скрытия.


Результат
Мы получили новый универсальный компонент, который можем использовать в наших продуктах.

Это решение помогло разгрузить информационную неопределенность пользователей наших систем.
Практически все предложенные решения не конфликтуют с архитектурой. Это значит, что мы проделали работу, которая не «утяжелила» систему — загрузка страниц и всех операций остаётся такой же быстрой.
В зависимости от реализации механизма загрузки можно сократить некоторые шаги (например, ожидание проверки и добавления файлов в систему).
Получили положительную обратную связь от команды эксплуатации на стороне заказчика нескольких наших продуктов.
Надеюсь, что статья была полезной для вас. Может у вас есть свои интересные кейсы, связанные с проектированием загрузчиков — буду рад вашим историям.)
Для связи пишите в telеgram: @Vpopo
aveselov
Код в студию, и как вы ускоряете загрузку чанки прямой аплоад в нджинкс?