Многие из нас сталкивались с оценкой сложности алгоритмов и хорошо представляют себе для чего она нужна. Но зачастую разработчики применяют О-нотацию исключительно к коду, забывая о том что алгоритмы существуют за его пределами. При этом, с ее помощью можно легко описать успех Инстаграма, предсказать, что веб-приложения займут доминирующую роль в ближайшем десятилетии и даже описать принцип работы мозга.
Недавно я столкнулся со статьей о пользе О-нотации в управлении проектом, которая и заставила меня написать данный текст. Я давно и успешно применяю оценку сложности в разработке и периодически сталкиваюсь с ограниченным пониманием ее разработчиками.
То о чем я говорю – это сама суть информационных технологий. Артемий Лебедев попробовал описать этот принцип, но получилось вот что, надеюсь у меня получится лучше.
Ключом к успеху является снижение сложности. Чем-то это напоминает смесь из принципов KISS и ТРИЗ. Суть изложенного подхода в формализации любого алгоритма и поиске математической симметрии там, где до сих пор принято пользоваться интуицией и творческим подходом.
Примеры
Для начала я приведу различные примеры применения принципа снижения алгоритмической сложности или же нарушения этих принципов. Возможно их будет больше чем вы ожидали. Вообще идеальным примером является конвейер Генри Форда, но давайте рассмотрим и другие:
Успех Instagram
Я давно занимаюсь фотографией и хорошо представляю себе процесс превращения снимка в продукт готовый к потреблению. Давайте перечислим шаги которые осуществляет пользователь для того чтобы поделиться красивой фотографией. Для этого он должен:
- Выгрузить снимок из фотоаппарата на компьютер:
- Физически подключить фотоаппарат к компьютеру/вставить карту памяти
- Открыть папку с фотографиями
- Создать папку назначения на компьютере
- Переместить файлы
- Выбрать подходящий снимок:
- Открыть программу-просмотрщик
- Отобрать лучшие снимки
- Выбрать один-два из понравившихся
- Конвертировать в формат подходящий для редактирования
- Обработать фотографию
- Запустить фоторедактор
- Перенести фотографию в фоторедактор
- Провести обработку (здесь количество вложенных шагов варьируется и может достигать нескольких десятков, если не сотен)
- Сохранить обработанный дубликат
- Поделиться результатом
- Выбрать подходящую площадку: flickr, 500px, vk, fb, tumblr.
- Загрузить фотографию в альбом или коллекцию, поместить на стене/ленте (зависит от сервиса).
- Придумать название или описание, указать теги (опционально).
В описании данного алгоритма я опустил то, что человек при этом должен разобраться в отличии JPEG от RAW, принципе работы фоторедактора, установить несколько программ и разобраться в десятках нюансов работы каждой из них и при этом обладать художественным вкусом для получения приличного результата после обработки.
Теперь давайте взглянем на этот процесс с точки зрения пользователя Instagram:
- Запустить Instagram
- Сделать фотографию
- Наложить фильтр
- Придумать описание, добавить метки
- Опубликовать
Изначально мы имеем 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)
dimkss
08.05.2016 19:56+3Статья очень хорошая. Хорошо бы еще обдумать разделение между обычными пользователями и продвинутыми. Т.е. для большинства достаточно шагов фото->фильтр->инстаграм->публикация, но при попытке сделать шаг хоть чуть-чуть в сторону, трудности начинаются невообразимые.
Вспоминается идея о том что 80% пользователей используют 20% возможностей программы, и продолжение этой идеи — что эти 20% для каждого пользователя разные.Rasifiel
09.05.2016 12:55Иногда проще потерять такого пользователя как можно более аккуратно и безболезненно, чем усложнять и замедлять процесс. Я прекрасно понимаю ограничения Инстаграма и поэтому не ожидаю чего-то большего чем быстро поделиться чем-то и если у меня возникает такая потребность я запускаю Лайтрум, экспортирую в Фликер и т.д.
zmeykas
09.05.2016 14:10-1жаль что зачастую приложения раздувают до огромного размера, желая угодить всем, вместо выпуска нескольких приложений для основных целевых аудиторий.
de1m
08.05.2016 23:57По моему мнению автор очень точно подметил про ТРИЗ и его (автора) пример про Instagram и про фотографии и про веб-приложения и то, что пишет Лебедев тоже описывается в ТРИЗ. Там говорится (не помню дословно), что любой механизм/аппарат и любая структура в целом развиваясь упрощается и уменьшается при этом стараясь не терять остальных качеств. В идеале должна остаться только функция (без самого механизма, который её осуществляет). Если к примеру посмотреть на программы, то понятно, что со временем всё скатится к веб-приложениям или чему-то на них похожему, потому что это банально проще. Надо а) Включить компьютер и б) включить программу вместо того как сейчас а) включить компьютер, б) Установить программу, в) включить программу ( это всё конечно очень упрощённо).
Sirikid
09.05.2016 01:14Если честно, я просто не хочу верить в такое будущее. Хочу взять порты, собрать бинарь и положить его в $PATH. Все это на удаленном ПК? Почему бы и нет, но не «все в браузере». Оффтоп конечно.
Ohar
09.05.2016 03:27Вы немного не поняли мысль. В вашем случае вы не хотите «взять порты, собрать бинарь и положить его в $PATH», а хотите работать так, будто «бинарь уже в $PATH и ничего брать и собирать и вообще заботиться об этом не нужно».
Sirikid
09.05.2016 16:53Можно сделать так что бы бинарь собирался/скачивался когда ты первый раз к нему обращаешься, это не проблема
maxpsyhos
09.05.2016 14:11+2Простите, а что, 3 раза нажать при установке «далее» — это так сложно? Да и выполняется она только один раз, а дальше как по п.1. И если рассматривать цепочку именно с такой стороны, то вы забыли пункт ВЫБРАТЬ программу, а он обычно занимает сильно больше времени, чем установка.
MonkAlex
09.05.2016 14:11+3Посидите без интернета неделю, я посмотрю на ваши веб-приложения.
frog
09.05.2016 16:34Через какое-то время это будет равносильно «посидите без электричества неделю». Т.е. отсутствие интернета станет чрезвычайной ситуацией. А пока да — проблема есть.
terryP
09.05.2016 16:38Так оффлайн режим в стандарте html5 существует уже давно. Какой-нибудь гугл докс всю неделю будет прекрасно работать без инета. В целом, работающее без инете веб-приложения это скорее вопрос желания разработчиков и затрат, а не неразрешимая проблема.
Newbilius
09.05.2016 17:26Какой-нибудь гугл докс всю неделю будет прекрасно работать без инета
Под «прекрасно работать» вы имеете ввиду «открывать те документы, что я открывал, когда был онлайн» или «заранее закэширует ВСЕ мои документы, что бы я мог оффлайн открыть любой из них»?
yamatoko
09.05.2016 14:11+1что нового в статье? а том, что все инструменты созданы для упрощения каких-то действий? это новость?
rumkin
09.05.2016 14:34-1Статья о том, что процесс создания нового можно и нужно формализовать и придать ему математическую строгость. Или о том, что успех продукта можно предсказать на этапе проектирования, имея достаточную теоретическую базу. Ну или о том, что некоторые программисты слишком увлекаются творчеством, забывая анализировать. Эта статья должна помочь тем, кто хочет научиться оценивать свой продукт с точки зрения потребителя, в отрыве от субъективных понятий "круто" или "отстой".
terryP
09.05.2016 16:48+4Как вам уже сказали, О-нотацию и алгоритмическая сложность в вашей статье вообще используется неправильно и отношения к тому что в ней описано по большому счету не имеет. А без идее связи с О-нотацией, все остальное превращается в капитанство вида «пользователям проще разбираться в меньшем количестве шагов», «делайте более простые приложения», «используете KISS», «анализируйте процесс проектирования и разработки» другими словами в то что и так каждый UX/веб дизайнер/разработчик/архитектор должен по идее знать. Извините, но тяжело серьезно воспринимать советы о «математическей строгости» от человека не понимающего О-нотации.
XanKraegor
09.05.2016 16:06Вместо того, чтобы говорить «массивный газовый шар, излучающий свет и удерживаемый силами собственной гравитации и внутренним давлением, в недрах которого происходят (или происходили ранее) реакции термоядерного синтеза», мы просто говорим «звезда»
Сильно сомневаюсь, что люди, впервые попытавшиеся назвать светящиеся в темное время суток точки на небе звездами, вкладывали в это слово такой смысл. Также как и сейчас множество людей не знают, что это газовый шар и там происходят какие-то реакции :)
Хорошее описание алгоритмической жадности мозга дано в книге Даниэла Канемана «Thinking, Fast and Slow». Чем-то напоминает предсказание ветвления в современных процессорах: мозг зачастую просто автоматически выбирает решение в соответствии со сложившимися паттернами (быстрая система, минимальная сложность), но, если нужно, включает осознанное обдумывание, связанное с несоизмеримо большими затратами усилий и привлечением драгоценного внимания.
shitpoet
09.05.2016 16:42+1всё-таки конструкция «если-то» не увеличивает алгоритмическую сложность по O-нотации, а вот цикломатическую сложность — увеличивает
из текста статьи может сложиться не совсем корректное впечатление.
amarao
09.05.2016 16:58+3Было O(n), осталось O(n). Что поменялось-то? Константы? Кого волнуют константы в O-нотации?
encyclopedist
вы точно понимаете что такое O-нотация? И то и другое эквивалентно O(1) (x — константа). Ваши доводы имеют смысл, только O-нотация тут не при чём.
В apt конечно же есть команда показывающая список установленных пакетов:
(не знаю правда в какой версии она появилась, может у вас старая версия?)
rumkin
Спасибо за уточнения.
Не знал, что она появилась, до сих пор по запросу list apt installed packages найти ее не так просто – только в одном месте я нешел упоминание об этой команде.
encyclopedist
Вообще я заметил что очень мало народу знает возможности
apt
и умеет ими пользоваться. Многие не знают даже о существовании очеловеченной комндыapt
вместоapt-get
apt-cache
и т.д. Я и сам только недавно узнал. И действительно, интернет тоже полон устаревших или переусложнённых советов.alexyr
О! Спасибо!
sasha1024
Так она (/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).