Является продолжением предыдущих публикаций. Не секрет, что при упоминании R в числе используемых инструментов вторым по популярности является вопрос о возможности его применения в «промышленной разработке». Пальму первенства в России неизменно держит вопрос «А что такое R?»


Попробуем разобраться в аспектах и возможности применения R в «промышленной» разработке.



Что такое промышленная разработка ПО?


Нисколько не удивляет, что под этим термином каждый понимает что-то свое. Начиная с «только C++» или «только java» и заканчивая «наличием плана продаж и роадмэпом на 10 лет вперед». Но без четкого определения термина дальше двигаться невозможно.


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


  • Артефакты с точки зрения менеджмента. Промышленная разработка ПО: профессиональная занятость в сфере разработки ПО в организации или подразделении, основная цель которого – создание программного продукта. Источник
  • Внутренние артефакты. Совокупность команды, управленческих методологий, используемых инструментов и соглашений по методам разработки ПО, позволяющих в заданный срок выдавать ПО с требуемыми характеристиками по функциональности, надежности, производительности и эргономичности. Это определение построено на основе трудов различных известных людей: Д.Кнут, С.Макконнелл, К.Вигерс, М.Фаулер, Э.Хант, Ф.Брукс, К.Бек, Дж.Спольски и др.

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


  • система управления требованиями (методология и инструменты);
  • система ведения проекта (методология и инструменты);
  • система контроля версий;
  • багтрекер
  • пр.

Таким образом, основные претензии можно переформулировать в контексте надежности («ага, интерактивная работа в консоли это вам не 24x7, да и писали все для академических исследований!»). Замечание в целом верное, но по слегка устаревшим данным. По факту в R в настоящее время сформирован набор пакетов и подходов, которые позволяют легко и элегантно делать приложения и в формате 24x7. Поэтому далее сфокусируемся на наиболее интересных моментах в задаче обеспечения надежности разрабатываемого ПО:


  • поддержка различных парадигм программирования;
  • отладка;
  • статический анализ кода;
  • логирование и анализ во время исполнения;
  • функциональное и юнит тестирование;
  • пакетирование и автоматизированная сборка;
  • система генерации документации.

Отчасти эти моменты пересекаются с областью «defensive programming».


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


Поддержка различных парадигм программирования


Существующий набор пакетов, дополняет и расширяет возможности base-R не только в части математических алгоритмов, но и в части парадигм разработки. Вынося за скобки вселенную tidyverse, имеет смысл упомянуть два пакета, расширяющих реализацию ООП и функционального программирования:


  • Система R6 классов. Детально ознакомиться с реализацией ООП на базе R6 можно по видео с конференции UseR! 2017. The R6 Class System, Video и естественно, на сайте CRAN. Там же можно почитать про сравнение характеристик по производительности по сравнению со штатной системой классов S3.

  • Функциональный подход. Пакет lambda.r реализует парадигму функционального программирования.

Если говорить о функциональном подходе, то реализация отдельного набора элементов такого подхода в пакете purrr в совокупности с pipe оператором %>% позволяет на практике очень сильно упростить и обезопасить обработку данных с существенным сокращением требуемого для этого объема кода. В качестве старта можно ознакомиться с хорошим докладом на эту тему: Happy R Users Purrr – Tutorial


Отладка


В дополнение к классическим инструментам отладки, хорошо описанным в статье «Debugging with RStudio» я бы упомянул следующие небесполезные инструменты:



Статический анализ кода


Тут все достаточно просто. Наиболее популярный инструмент — lintr@CRAN или lintr@github.
Lintr интегрируется с RStudio IDE, чтобы не повторяться, детали можно посмотреть в ветке Lintr integration with RStudio.


Логирование и анализ во время исполнения


Логирование


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


Для задачи логирования наиболее удобен пакет futile.logger. Семантика log4j многим известна и не требует изучения нового. Из полезно-удобных дополнений/расширений я бы выделил следующие:


  1. Конфигурация логгера в форме flog.appender(appender.tee(log_name)) позволяет включать одновременный вывод и в файл и в консоль.
  2. Для формирования сложных строк, содержащих значения переменных, вместо base::paste гораздо удобнее использовать glue::glue. Например, строка paste0(" FROM", ch_db$table, "WHERE ", where_string, sep=" ") превращается в одну форматную строку glue(" FROM {ch_db$table} WHERE {where_string}"). С учетом векторизации glue печать табличной выборки также превращается в одну строчку. Детали можно посмотреть в анонсе glue 1.2.0
  3. Для вывода сообщений, выдаваемых функциями в stdout можно использовать функцию capture.output(fun...).
  4. Для вывода времени исполнения блока команд весьма удобно использовать функции tic(), toc() из пакета tictoc. При этом финализирующую функцию сразу включать в логгер в форме такой конструкции: flog.info(glue("Data query response time: {capture.output(toc())}"))

Real-time валидация


В целом, особенно в языках с динамической типизацией, правилом хорошего тона является проверка данных, поступающих на обработку в ту или иную функцию. По-хорошему, проверку следует разделить на два этапа: физическая проверка (данные требуемого типа) и логическая проверка (содержание данных правильного типа также следует установленным требованиям). Время на исполнение логической проверки может быть на порядки больше, нежели на физическую. Элементарный пример — на этапе физической проверки мы смотрим, что на вход пришел вектор чисел с плавающей точкой, а на этапе логической проверки смотрим, что все элементы вектора неотрицательны.


В R для этого все есть и даже с весьма неплохим выбором. Упомяну только самые интересные и перспективные пакеты. checkmate для физической проверки и assertr, validate для логической.


Приятно, что в отличие от assertive, реализация checkmate изначально ориентирована на скорость и минимальный оверхед, о чем можно прочесть в публикации «checkmate: Fast Argument Checks for Defensive R Programming».
Ну и возможность написания компактных правил валидации в стиле regexp средствами qassert очень радует, поскольку позволяет свернуть типичную функцию проверки на 2 строки до строки в несколько символов.


В части логической проверки — тут каждый может выбрать удобный ему способ. Все зависит от того, какие рода данные, идет ли обработка независимо или в конвейере (pipe), что именно нужно проверять.


В зависимости от того, что требуется по логике программы, можно либо делать проверку на соответствие условиям с получением TRUE/FALSE и последующим ветвлением логики, либо генерировать exception (assert).


Обработка исключений


Механизм генерации исключений несомненно полезен при работе с данными, а подробный вывод сопутствующей информации как нельзя кстати при интерактивной работе в консоли. Однако при переходе к потоковому исполнению останов программы при возникновении ошибки совершенно не нужен, а разнообразие в способах формирования диагностических сообщений начинает утомлять при создании обработчиков.
Обработка исключений штатными механизмами tryCatch хорошо описана в книге «Advanced R». Более интересным и полезным применительно к обработке данных в программном режиме является два следующих расширения:


  • обработка исключений без останова конвейера (pie);
  • унификация ответов от функций.

И тот и другой функционал реализован в пакете purrr семейством функций-оберток safely. Получение от любой функции стандартизованного списка с полями error/result позволяет не прерывать потоковую обработку, а обработать возникшие исключения и ошибки после завершения конвейера. Вовсе нет необходимости всегда бить в колокол и поднимать исключение, если в ходе обработки вектора возникло деление на 0. Достаточно пометить некорректный элемент и перейти к следующему. Такая инкапсуляция обработки исключений позволяет вместо нескольких десятков строк кода, призванных учету непредвиденных ситуаций при обработке данных свести все к одной обертке. Меньше код, меньше избыточной вариативности — стабильней результат.


Хорошо и кратко возможности по использованию safely были описаны в блоге RStudio: purrr 0.2.0 by Hadley Wickham + документация.


Функциональное и юнит тестирование


Пакет testthat. Изучение можно начать со статьи «testthat: Get Started with Testing», продолжить CRAN и книгами Hadley Wickham, а также книгой «Testing R Code». С учетом положений, упомянутых выше, я бы перекладывал при чтении функции из assertive на функции из пакета checkmate. Автотесты можно писать как для пакетов, так и для отдельных функций.


Пакетирование и автоматизированная сборка


Просто констатируем, что есть но не все об этом знают. Сборка, валидация, документирование, проверка и пр., все интегрировано RStudio IDE. Кратко охвачено в статье «Building, Testing, and Distributing Packages». Досконально все описано в отличной книге Hadley Wickham: «R packages». Полезным может оказаться применение хелпер-пакета usethis


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


Система генерации документации


Просто констатируем, что есть для пакетов, но не все об этом знают. Построена на базе roxygen, интегрировано с RStudio IDE.
Досконально все описано в отличной книге Hadley Wickham: «R packages».


Заключение


Сейчас R очень активно развивается. Каждую неделю появляются новые полезные функции, пакеты, подходы или улучшаются существующие. В задачах, связанных с обработкой данных указанный в публикации набор пакетов позволяет писать на R быстрый, стабильный, компактный и прогнозируемый код. Год назад этих пакетов было меньше, что будет в конце 2018 — время покажет.


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


Что касается скорости, то, как всегда, этот вопрос относителен. 2 дня разработки + 10 секунд на исполнение на R много меньше, чем 2 недели разработки + 0.1 секунда на исполнение, например, на Java. О скорости необходимо говорить в контексте. Для функций, требующих быстроты исполнения, есть возможность реализовать ее на C++ не выходя за границы R путем применения пакета Rcpp. С кратким обзором возможностей можно ознакомиться также в одной из статей автора: «Extending R with C++: A Brief Introduction to Rcpp».


Задач по разнообразной обработке данных (от сбора до визуализации) становится все больше. Почему бы не взглянуть в сторону R?


Предыдущая публикация — «R, Asterisk и платяной шкаф».

Комментарии (20)


  1. Crandel
    13.11.2017 17:58

    В чем преимущества R перед Python? На последнем все уже давно придумано, весь жизненный цикл, есть нормальные IDE, тоже целая куча библиотек и самое главное — программистов знакомых с ним намного больше


    1. i_shutov Автор
      13.11.2017 18:21

      Python — замечательная штука, да и вообще все уже придумано до нас :), но


      1. Абстрактно все сферические кони хороши. Преимущества и недостатки всегда рассматривают в контексте.
      2. Если речь идет о комплексном DS приложении, которое должно еще и предоставлять результаты простым пользователям в виде дашбордов, приложений, отчетов, hard-copy артефактов, то наличие Shiny начинает сильно перевешивать.
      3. Результат работы "поверхностно знакомых" специалистов, как правило, весьма посредственный. Программирование лишь частный случай. Настоящих профессионалов в любом деле всегда мало.
      4. Куча библиотек — это просто куча битов и байтов, до тех пор, пока на собственном опыте не наберешь шишки и не поймешь, что хорошо, что плохо и как это использовать. Наличие нескольких сетей фитнес-центров никак не сказывается на физической форме отдыхающих на диване. Кстати, аналогов stringi\stringr в python я пока не нашел. Может, конечно, не достаточно сильно искал...
      5. Никто и не говорит, что Python плохой. Это отличный язык и я с удовольствием периодически его использую с 2006 года. Речь о том, что R сильно недооценен в России. Хорошо знать один язык. А два — лучше.


      1. Crandel
        13.11.2017 18:34

        Если речь идет о комплексном DS приложении, которое должно еще и предоставлять результаты простым пользователям в виде дашбордов, приложений, отчетов, hard-copy артефактов, то наличие Shiny начинает сильно перевешивать.

        Jupiter Dashboards
        Plotly
        Плюс на питоне можно веб сервер поднять(Django) и показывать графики всем желающим используя bokeh


        stringi\stringr

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


        Хорошо знать один язык. А два — лучше.

        А вот это уже спорный вопрос, но тут я не буду никого ни в чем убеждать)


      1. i_shutov Автор
        14.11.2017 12:06

        Да, насчет Питона в DS был еще тот холивар, вот на сейчас точно уже не скажу, закончился ли он или где-то еще есть засады. Надоело находится в ожидании "вот-вот" все случится.


        На протяжении нескольких лет камнем преткновения являлся вопрос портирования DS библиотек с 2.7 на 3.x.
        Появлялись посты типа такого: "Will Scientists Ever Move to Python 3?" и сайты типа такого: "Python 3 Readiness".


        И если обычные разработчики активно переходили на 3.x ветку и пользовались всеми новыми фичами, то DS до последнего держалась за 2.7.


        При этом все понимали, что с переходом на 3.x придется от многих привычек отвыкать и переучиваться. Мрачное ощущение тратить время и силы на изучение и работу с инструментом дни которого сочтены и дата окончания задекларирована.


    1. OlegUV
      14.11.2017 11:41

      Есть опыт работы и с Python и с R. Главное, что даёт R +shiny etc — скорость получения презентабельного продукта с нуля (конечно, под целевые задачи). Скорость в R больше, чем в Python, пожалуй, на порядок.


    1. borisxm
      15.11.2017 08:26

      Действительно, в Python уже есть библиотеки практически на все случаи жизни. На R попробовал писать просто ради интереса. Оказалось, что для обработки данных и расчетов он ничуть не хуже Python: простой синтаксис, куча библиотек, вполне вменяемая RStudio. Далее, дал молодому специалисту неделю на изучение и практику, после чего он и схожий по квалификации человек реализовали не самую тривиальную задачу на R и Python соответственно. Цифровой результат и графики, понятно, получились одинаковыми, но реализация на R получилась компактнее, заняла на, примерно, треть меньше времени, а читабельность кода, по субъективным оценкам, выше чем на Python.

      Другим плюсом является прозрачная интеграция C++ кода, что для нас крайне важно.

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


      1. i_shutov Автор
        15.11.2017 10:06

        Если что-то смущает, можно обсудить и обменяться возможными вариантами решения. Скайп/телеграм/почта.
        Это всегда полезно. И потому что помогает расширить community и потому что может привести к необходимости поиска ответа, переосмыслению устоявшихся ранее подходов.


        На текущий момент мы постоянно смотрим новую информацию по пакетам R, интересные методики и реализации. Если что-то появляется интересное и более эффективное, проверяем и без жалости выкидываем старое. Из последних интересных перемещений (в ряде задач) с saveRDS/readRDS на http://www.fstpackage.org/


        1. borisxm
          15.11.2017 10:38

          Если что-то смущает, можно обсудить и обменяться возможными вариантами решения.

          Смущает, в основном, возможность написать
          x < -2
          вместо
          x <- 2
          и не получить никаких предупреждений.


  1. i_shutov Автор
    13.11.2017 18:49

    1. В самом начале публикаций давал пояснение, почему мы перешли на R. Ничего с того момента не изменилось.
    2. Я не говорю об отдельных графиках, речь идет про полноценное приложение. С таблицами, закладками, элементами управления, контекстным drill-down, генерацией всевозможных всеформатных выгрузок, интеграцией с кучей внешних систем. Например, как описано в прошлой статье.
    3. Про stringi\stringr в картинках можно посмотреть здесь. Насчет графики — я подходил несколько раз к matplotlib аж с 2008, и все разы он не дотягивал до требований, приходилось откладывать. А функционал и семантика ggplot позволяет рисовать почти любые графики, какие только пользователям взбредут в голову. Приходится их просить не сдерживать себя в фантазиях :) А то, кроме кружочков ничего придумать не могут.


  1. Myonin
    13.11.2017 20:08

    Очередной коллектив отечественных разработчиков перешёл на R. Теперь вас двое.


    1. i_shutov Автор
      13.11.2017 23:02

      Артем, в смысле "нас" двое? Нет, много больше :)


      1. Myonin
        13.11.2017 23:14

        Хотелось бы верить ) Сам большой фанат R, но все знакомые мне по реальной жизни data scientists/engineers работают на Python. Недавно искал работу в МСК, из дюжины где-то компаний, которые посетил, R использует только одна. И то только для создания прототипов.


  1. KEugene
    13.11.2017 21:55

    Мне кажется пропаганду языка R необходимо вести не сколько среди разработчиков, а, скорее среди сотрудников финансово-экономической службы и аналитиков. Плюс, менеджмент среднего и верхнего уровня. На соответствующих ресурсах.
    Может, я не прав, но, как по мне, то программисты довольно консервативны. Особенно те, что работают в поддержке крупных компаний. Если у них есть некий отлаженный процесс, сформировавшийся набор используемых заготовок и билиотек, то сложно будет заставить все переделать на некой новой платформе. А подавляющей доле экономистов и аналитиков, практически, нечего терять кроме Экселя.


    1. i_shutov Автор
      13.11.2017 23:14

      По моему опыту, там вообще вся эта тема фиолетова. Там надо говорить об исполнении плана, марже, воронке продаж, клиентах, соблюдению KPI и РЕЗУЛЬТАТАХ (иногда никто не знает, как они должны выглядеть, но они обязательно должны быть).


      Движение снизу гораздо интереснее. Тем более, что специалист, который ничего нового не изучает и по сторонам не смотрит в один прекрасный день останется на обочине. Видел такие примеры тотальной неожиданной дисквалификации среди разработчиков. И это не "привилегия" разработчика, это касается множества обычных профессий, таких как, парикмахер, стоматолог, учитель, автомеханик и многие другие.


      1. KEugene
        13.11.2017 23:31

        Я с Вами не соглашусь. Вероятно, многое зависит от компании, ее политики и руководства. У меня есть практический опыт «внедрения» новых технологий именно среди сотрудников финансово-экономической службы крупного холдинга. Если сотрудники решают творческие задачи, а не лабают таблички «цена — количество — сумма», если есть четко описанные процедуры по тем или иным процессам, то как исполнители, так и их руководители стараются найти резервы. Задачи усложняются, их число растет, а человеко-часы подразделения остаются неизменными. Достаточно показать: вот модель, выполненная вами в экселе и ее создание заняло 3 дня, а вот она же, реализованная с помощью Azure ML в бесплатном аккаунте за 1 день. Вот анализ полевых работ за два сезона в Экселе. Ее открытие занимает три минуты и делалась она неделю, а вот такой же анализ, сделанный на python, делающий пересчет за 10 секунд и разработанный за два дня. Именно так я и сделал. Пара человек загорелась новыми идеями, начальник выделил им рабочее время(!) на изучение новшеств. Достаточно было продемонстрировать их же живые примеры по принципу «было — стало».


        1. i_shutov Автор
          14.11.2017 10:12

          В такой форме комментария я 100% соглашусь. У меня именно таких примеров есть некоторое количество. Я ровно с этой целью и трачу время на публикации, чтобы заинтересованные люди могли ознакомиться с интересными возможностями, увидеть, что задачи решаются, причем решаются весьма элегантно и попробовать самим применить. А дальше уже как раз по сценарию внутренних коммуникаций в своей компании. Ведь неизвестному человеку извне весьма сложно пробиться к финансовым сотрудниками крупного холдинга :).


          А бизнес, все-таки, интересует только результат. Демонстрация решения именно их задач на именно их данных — ключевой момент. Все остальное — пустой звук и игры разума.


  1. kuragami
    14.11.2017 10:06

    Я совсем не специалист по R (от слова вообще), но за последний год он не раз и не два помогал мне в NLP и оценки алгоритмов для ML. Для моих крайне нетребовательных по скорости задач, R мне показался наиболее лаконичным и простым языком. Жаль, что ру—коммьюнити очень не большое. Доки с CRAN конечно читаю, но все равно 99% провожу на SO.


    1. WTYPMAH
      15.11.2017 11:52

      r bloggers тоже хорошее комьюнити


  1. WTYPMAH
    14.11.2017 10:12

    Скажите, пожалуйста, какой размер команды разработки / поддержки? Не из праздного любопытства — от размера команды будет зависеть понимание масштаба поддержки. На сколько я понимаю по вашим предыдущим статьям, широко используется shiny и мне интересно как осуществляется поддержка и bug-fixing достаточно большой командой, учитывая практически полную связь бэка и фронта. В моем понимании каждый член команды должен знать архитектуру и функциональность практически ВСЕГО приложения и всех его частей для эффективной поддержки. В маленьких командах это может не быть проблемой, но в распределённых — большой вопрос…


    1. i_shutov Автор
      14.11.2017 10:19

      Поскольку стек у нас чуть больше, тут и go\python\Clickhouse\реляционные БД\JS+CSS+HTML, то, в зависимости от проекта, получается вовлеченными 4-6 человек разработчиков. На R получается 1-3 в зависимости от масштаба. И обязательно нужны люди, владеющие предметной областью. Сами shiny приложения получаются весьма компактными. При избыточном коде — вынос излишков в пакеты\функции и тотальное обкладывание автотестами и ассертами. Если возникают нюансы с пакетами — общаемся через github c разработчиками. Очень ждем выхода в продуктив асинхронных функций в shiny: An informal intro to async Shiny by Joe Cheng