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


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


То о чем я говорю – это сама суть информационных технологий. Артемий Лебедев попробовал описать этот принцип, но получилось вот что, надеюсь у меня получится лучше.


Ключом к успеху является снижение сложности. Чем-то это напоминает смесь из принципов KISS и ТРИЗ. Суть изложенного подхода в формализации любого алгоритма и поиске математической симметрии там, где до сих пор принято пользоваться интуицией и творческим подходом.


Примеры


Для начала я приведу различные примеры применения принципа снижения алгоритмической сложности или же нарушения этих принципов. Возможно их будет больше чем вы ожидали. Вообще идеальным примером является конвейер Генри Форда, но давайте рассмотрим и другие:


Успех Instagram


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


  1. Выгрузить снимок из фотоаппарата на компьютер:
    1. Физически подключить фотоаппарат к компьютеру/вставить карту памяти
    2. Открыть папку с фотографиями
    3. Создать папку назначения на компьютере
    4. Переместить файлы
  2. Выбрать подходящий снимок:
    1. Открыть программу-просмотрщик
    2. Отобрать лучшие снимки
    3. Выбрать один-два из понравившихся
    4. Конвертировать в формат подходящий для редактирования
  3. Обработать фотографию
    1. Запустить фоторедактор
    2. Перенести фотографию в фоторедактор
    3. Провести обработку (здесь количество вложенных шагов варьируется и может достигать нескольких десятков, если не сотен)
    4. Сохранить обработанный дубликат
  4. Поделиться результатом
    1. Выбрать подходящую площадку: flickr, 500px, vk, fb, tumblr.
    2. Загрузить фотографию в альбом или коллекцию, поместить на стене/ленте (зависит от сервиса).
    3. Придумать название или описание, указать теги (опционально).

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


Теперь давайте взглянем на этот процесс с точки зрения пользователя Instagram:


  1. Запустить Instagram
  2. Сделать фотографию
  3. Наложить фильтр
  4. Придумать описание, добавить метки
  5. Опубликовать

Изначально мы имеем 15 шагов и при этом некоторые из-них могут содержать множество "вложенных". Благодаря Instagram сложность снизилась с 15+x действий до 5, а затраты времени снизились с 30–40 минут, до нескольких минут. Это колоссальный выигрыш.


Пример программы


Существует утилита NVM для разработчиков на Node.js. Она помогает устанавливать разные версии Node.js и переключаться между ними с помощью двух комманд install и use. Тот же самый процесс установки свежей версии Node.js на Ubuntu, требует как минимум трех шагов и двух принятий решений, а о переключении между версиями я и говорить не хочу.


При этом для работы NVM патчит файл ~/.profile (чтобы загружаться каждый раз, как пользователь открывает консоль), для этого в нем содержится около тысячи строк достаточно сложного кода с множеством ветвлений для разных ОС. При этом в unix есть механизм стандартного расширения – это директория ~/.profile.d, куда нужно складывать такие скрипты, тогда установка и удаление расширения занимает всего две строчки кода:


# Добавить
cp some-init-script.sh ~/.profile.d/
# Удалить
rm ~/.profile.d/some-init-script.sh

Конечно, не все системы включают поддержку ~/.profile.d поэтому вы можете легко найти множество программ которые патчат ~/.profile и каждый раз программисты тратят время на собственную реализацию такого патча для разных систем. Более того определить наличие патчей других разработчиков становится просто невозможно из-за обилия кастомных решений. Я называю это явление too custom, когда единое решение не может быть внедрено из-за чрезмерного количества ветвлений, которые нужно будет учесть.


Кстати, абсолютно такая же ситуация с автокомплитом. Многие программы не содержат скрипт автодополнения, потому что он требует прав супер-пользователя при установке, хотя иногда программа должна быть установлена от имени пользователя и тогда положить скрипт автодополнения можно в ~/.bash_completion.d, но об этом мало кто знает.


Почему веб-приложения будут доминировать

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


И т.д. и т.п.


Очень много сфер и компаний применяют этот принцип, перечислять можно очень долго DevOps, UX, PayPal, AppStore, iTunes, Github...


Мозг


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


Солнце встает на Востоке

и развернем его


Массивный газовый шар, излучающий свет и удерживаемый силами собственной гравитации и внутренним давлением, в недрах которого происходят реакции термоядерного синтеза, являющийся центральным объектом Солнечной системы, появляется из-за линии горизонта со стороны света в направлении которой вращается планета Земля.

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


Оценка сложности


Любой выбор – это увеличение сложности.

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


  • Необходимо расписать каждый шаг даже с виду незначительный.
  • Учесть компетенцию пользователя и внести получение этой компетенции в сложность алгоритма. Можно разделить пользователей по категориям.
  • Каждый момент принятия решений пользователем должен быть проанализирован. Любой выбор усложняет алгоритм.
  • Оцените ветвление алгоритма (все конструкции "если-то" создают новую ветку), если какие-то ветви являются наиболее часто-используемыми примените к ним механизм упрощения: придумайте термин, команду, сделайте отдельную кнопку или панель быстрого доступа/настроек/редактирования/добавления/удаления.

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


После того как составлен план, нужно классифицировать действия и выбрать подходящий способ упрощения.


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


Оценка эффективности


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


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

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


  1. encyclopedist
    08.05.2016 19:51
    +34

    1. сложность снизилась с O(15+x) до O(5)

      вы точно понимаете что такое O-нотация? И то и другое эквивалентно O(1) (x — константа). Ваши доводы имеют смысл, только O-нотация тут не при чём.


    2. В apt конечно же есть команда показывающая список установленных пакетов:


      apt list --installed

      (не знаю правда в какой версии она появилась, может у вас старая версия?)


    3. В новой версии Убунту как раз появился механизм Snap, который напоминает приложения в MacOS X


    1. rumkin
      08.05.2016 20:25

      Спасибо за уточнения.


      1. Не знал, что она появилась, до сих пор по запросу list apt installed packages найти ее не так просто – только в одном месте я нешел упоминание об этой команде.


      2. Snap очень похож на то, о чем я говорил, но он все-так же размазывает приложение по операционной системе и распихивает файлы так, что простым удалением директории приложения не обойдешься. И велика вероятность, что система до установки не будет идентична системе после удаления.


      1. encyclopedist
        08.05.2016 20:31
        +3

        Вообще я заметил что очень мало народу знает возможности apt и умеет ими пользоваться. Многие не знают даже о существовании очеловеченной комнды apt вместо apt-get apt-cache и т.д. Я и сам только недавно узнал. И действительно, интернет тоже полон устаревших или переусложнённых советов.


        1. alexyr
          08.05.2016 21:30

          О! Спасибо!


        1. sasha1024
          09.05.2016 14:10

          Так она (/usr/bin/apt) появилась только в апреле 2014 (http://metadata.ftp-master.debian.org/changelogs/main/a/apt/apt_1.0.9.8.3_changelog).
          И ещё до конца не стабилизировалась (если я правильно понимаю, то разные команды внутри apt, например apt install, apt show, apt list, должны быть «shortcut'ами» на соответствующие команды внутри apt-*, например apt-get install и apt-cache show — но часть команд, например list и edit-sources, ПОКА вделаны в сам apt; см. man apt).


  1. dimkss
    08.05.2016 19:56
    +3

    Статья очень хорошая. Хорошо бы еще обдумать разделение между обычными пользователями и продвинутыми. Т.е. для большинства достаточно шагов фото->фильтр->инстаграм->публикация, но при попытке сделать шаг хоть чуть-чуть в сторону, трудности начинаются невообразимые.
    Вспоминается идея о том что 80% пользователей используют 20% возможностей программы, и продолжение этой идеи — что эти 20% для каждого пользователя разные.


    1. Rasifiel
      09.05.2016 12:55

      Иногда проще потерять такого пользователя как можно более аккуратно и безболезненно, чем усложнять и замедлять процесс. Я прекрасно понимаю ограничения Инстаграма и поэтому не ожидаю чего-то большего чем быстро поделиться чем-то и если у меня возникает такая потребность я запускаю Лайтрум, экспортирую в Фликер и т.д.


    1. zmeykas
      09.05.2016 14:10
      -1

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


  1. de1m
    08.05.2016 23:57

    По моему мнению автор очень точно подметил про ТРИЗ и его (автора) пример про Instagram и про фотографии и про веб-приложения и то, что пишет Лебедев тоже описывается в ТРИЗ. Там говорится (не помню дословно), что любой механизм/аппарат и любая структура в целом развиваясь упрощается и уменьшается при этом стараясь не терять остальных качеств. В идеале должна остаться только функция (без самого механизма, который её осуществляет). Если к примеру посмотреть на программы, то понятно, что со временем всё скатится к веб-приложениям или чему-то на них похожему, потому что это банально проще. Надо а) Включить компьютер и б) включить программу вместо того как сейчас а) включить компьютер, б) Установить программу, в) включить программу ( это всё конечно очень упрощённо).


    1. Sirikid
      09.05.2016 01:14

      Если честно, я просто не хочу верить в такое будущее. Хочу взять порты, собрать бинарь и положить его в $PATH. Все это на удаленном ПК? Почему бы и нет, но не «все в браузере». Оффтоп конечно.


      1. Ohar
        09.05.2016 03:27

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


        1. Sirikid
          09.05.2016 16:53

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


    1. maxpsyhos
      09.05.2016 14:11
      +2

      Простите, а что, 3 раза нажать при установке «далее» — это так сложно? Да и выполняется она только один раз, а дальше как по п.1. И если рассматривать цепочку именно с такой стороны, то вы забыли пункт ВЫБРАТЬ программу, а он обычно занимает сильно больше времени, чем установка.


    1. MonkAlex
      09.05.2016 14:11
      +3

      Посидите без интернета неделю, я посмотрю на ваши веб-приложения.


      1. frog
        09.05.2016 16:34

        Через какое-то время это будет равносильно «посидите без электричества неделю». Т.е. отсутствие интернета станет чрезвычайной ситуацией. А пока да — проблема есть.


      1. terryP
        09.05.2016 16:38

        Так оффлайн режим в стандарте html5 существует уже давно. Какой-нибудь гугл докс всю неделю будет прекрасно работать без инета. В целом, работающее без инете веб-приложения это скорее вопрос желания разработчиков и затрат, а не неразрешимая проблема.


        1. Newbilius
          09.05.2016 17:26

          Какой-нибудь гугл докс всю неделю будет прекрасно работать без инета

          Под «прекрасно работать» вы имеете ввиду «открывать те документы, что я открывал, когда был онлайн» или «заранее закэширует ВСЕ мои документы, что бы я мог оффлайн открыть любой из них»?


  1. yamatoko
    09.05.2016 14:11
    +1

    что нового в статье? а том, что все инструменты созданы для упрощения каких-то действий? это новость?


    1. rumkin
      09.05.2016 14:34
      -1

      Статья о том, что процесс создания нового можно и нужно формализовать и придать ему математическую строгость. Или о том, что успех продукта можно предсказать на этапе проектирования, имея достаточную теоретическую базу. Ну или о том, что некоторые программисты слишком увлекаются творчеством, забывая анализировать. Эта статья должна помочь тем, кто хочет научиться оценивать свой продукт с точки зрения потребителя, в отрыве от субъективных понятий "круто" или "отстой".


      1. terryP
        09.05.2016 16:48
        +4

        Как вам уже сказали, О-нотацию и алгоритмическая сложность в вашей статье вообще используется неправильно и отношения к тому что в ней описано по большому счету не имеет. А без идее связи с О-нотацией, все остальное превращается в капитанство вида «пользователям проще разбираться в меньшем количестве шагов», «делайте более простые приложения», «используете KISS», «анализируйте процесс проектирования и разработки» другими словами в то что и так каждый UX/веб дизайнер/разработчик/архитектор должен по идее знать. Извините, но тяжело серьезно воспринимать советы о «математическей строгости» от человека не понимающего О-нотации.


  1. XanKraegor
    09.05.2016 16:06

    Вместо того, чтобы говорить «массивный газовый шар, излучающий свет и удерживаемый силами собственной гравитации и внутренним давлением, в недрах которого происходят (или происходили ранее) реакции термоядерного синтеза», мы просто говорим «звезда»

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

    Хорошее описание алгоритмической жадности мозга дано в книге Даниэла Канемана «Thinking, Fast and Slow». Чем-то напоминает предсказание ветвления в современных процессорах: мозг зачастую просто автоматически выбирает решение в соответствии со сложившимися паттернами (быстрая система, минимальная сложность), но, если нужно, включает осознанное обдумывание, связанное с несоизмеримо большими затратами усилий и привлечением драгоценного внимания.


  1. shitpoet
    09.05.2016 16:42
    +1

    всё-таки конструкция «если-то» не увеличивает алгоритмическую сложность по O-нотации, а вот цикломатическую сложность — увеличивает

    из текста статьи может сложиться не совсем корректное впечатление.


  1. amarao
    09.05.2016 16:58
    +3

    Было O(n), осталось O(n). Что поменялось-то? Константы? Кого волнуют константы в O-нотации?