среда, 28 декабря 2011 г.

Астрономия - Фото 2011 - VIII


пятница, 23 декабря 2011 г.

Джеф Раскин — Интерфейсы

Прочитал книгу Джефа Раскина: «Интерфейс: новые направления в проектировании компьютерных систем».

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

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

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

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

Во время прочтения интуитивно становится понятно, почему люди выбирают Macintosh вместо Windows, и почему «Windows must die». В чем же интерфейсы Microsoft ужасны и чему они могут поучиться у Mac'ов.

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

Интересно, что подход к сохранению паролей Раскина был очень похож на мой 2-й способ (; — генерация трех произвольных слов из английского языка.


суббота, 10 декабря 2011 г.

Разработка с помощью примеров и на основе правил

ML, наслоившись на Лерера, и на опыт разработок различных систем, нарисовало противоречие двух различных подходов в разработке. Это разработка на основе правил (формулировка фиксированных требований) и с помощью примеров (на основе единичных примеров).

Разработка с помощью примеров

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

Например.

Пользователь: «Хочу, чтобы я нажал на кнопочку, а письмо ушло по вот этому адресу.» Здесь пользователя не волнует, что будет если письмо будет очень большое. Или если сервер будет не доступен. Ему в формулировке важно, чтобы было создано письмо и оно дошло.

При тестировании таких требований происходит то же самое. Создается тест, в котором создается письмо, отправляется на ящик, проверяется в приемнике. Если оно дошло — значит все работает.

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

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

Грамотный программист в отличие от новичка в состоянии подобрать такую функцию, которая не только бы удовлетворяла всем примерам, но и имела бы грамотный запас прочности по расстоянию (не скатывалась в Overfitting и Underfitting). И кроме того, он в состоянии найти эту функцию быстро.

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

int sqr( int x )
{
    return x*x;
}
То тест будет выглядеть например так:
int
test_sqr( int x  )
{
    const int result = sqr( 1 );
    assert_true(result > 0);
    return result;
}

void
test()
{
    assert_true( test_sqr(1) == 1 );
    assert_true( test_sqr(4) == 16 );
    assert_true( test_sqr(-1) == 1 );
    assert_true( test_sqr(0) == 0 );
}

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

Разработка на основе правил

Основой для разработки является набор правил, которые должны быть выполнены. Как аксиомы в математике, от которых можно отталкиваться и строить какие-либо другие утверждения.

Примеры правил:

  • В системе реакция на события происходит с задержкой не более 100 мс.
  • Отправленное сообщение если не доставлено в течение 1 с, то оно не будет доставлено вообще.
  • Стрелка не должна переводиться в случае, если её секция занята (перевод стрелки под поездом).
  • При входе в функцию аргумент не должен превышать 100.

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

Например если взять нашу функцию sqr, то с применением метода predicate Abstraction и выводом постусловия сверху вниз можно вывести постусловие из предусловия. Например если на входе аргумент находится в диапазоне от 0 до 10, (предусловие {0 < x < 10}), то на выходе аргумент будет находится в диапазоне от 0 до 100 (постусловие {0 < x < 100}).

Другое применение: если мы требуем, чтобы на выходе не было переполнения ({-INT_MAX < x < INT_MAX}), то с помощью правил вывода можно рассчитать предусловие:

{-INT_MAX < x*x < INT_MAX}

{x*x < INT_MAX}

{-sqrt(INT_MAX) < x < sqrt(INT_MAX)}

Таким образом получить предусловие, для которого вычисление x*x не даст переполнения.

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

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

Разница подходов на характерных примерах

Тренировка на примерах и вывод нужной функции из аксиом

Подход на примерах

  • Формулируется что-то вида «оно-интуитивно-должно-работать».
  • Запускается тестовый пример (на доске, в тетрадке, в голове, …). Смотрится, как оно по идее должно отработать. Интуитивно понимается, что скорее всего вот здесь проблема, а здесь возможно долго кодить, а здесь наверное надо-ещё-подумать.
  • Если обнаружены проблемы на предыдущем шаге, то начинается размышление чего-исправить-чтобы-заработало.
  • Добавляется ещё много-много-примеров. Пока не появится уверенность, что все должно работать.
  • Если ничего не получается, то идет переход к первому шагу с попыткой переписать все с нуля. Или берется таймаут до новых идей.

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

Эффективность работы определяется: способностью интуитивно (то есть, на основе опыта по Лереру) подобрать решение, способностью интуитивно собрать хорошие тестовые примеры (качественные тестировщики и идееобламыватели). Конечно же, делать все это надо быстро, с минимумом затрат времени и ресурсов.

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

Подход на системе правил

В идеале этот подход представляет построение программы на основе требований ТЗ. Но в таком виде оно выполнимо только для очень маленьких программ. Десятки операторов. Это в случае, если построение идет вручную. При автоматизации возможно улучшить это дело на порядок.

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

В синтезе с подходом на примерах получается приблизительно следующее:

  • Исследование предметной области (ТЗ, железо, библиотеки, …) и установка правил (трафик не превышает 100 транзакций в секунду; таблица не должна содержать более 1М записей; введение индекса по такому-то полю позволит выполнить select со сложностью log N).
  • Формулировка варианта решения с учетом всех правил. Если правила невыполнимы, то задача в таком ключе не решается и надо их пересмотреть.
  • Формулировка дополнительных правил исходя из варианта решения.
  • Прогон на тестовых примерах (не важно где, в уме или на стенде).

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

Особенность железной дороги в том, что разрабатываемый софт нижнего уровня работает на одном и том же железе. С минимумом привлечения сторонних библиотек. При конкретных и не меняющихся требованиях заказчика. Все намного более жестко детерминировано. В банковских системах эти моменты теряют смысл. Требования к проекту могут измениться через неделю после старта разработки при проведенном проектировании. Исследовать свойства предметной области чаще не удается, чем удается. Перед внедрением внезапно заказчику хочется прикрутить какую-нибудь рюшечку. В документации написано, что на запрос должен прийти ответ «Пиво», а на самом деле приходит «Жопа». В договоре темп 100 транзакций в секунду, но почему-то раз в сутки в зависимости от фазы Луны происходит всплеск в 200 шт в секунду. Когда показываешь логи с фактом, то оказывается, что лучше допилить приложение. И т.д. и т.п.. В таких условиях сформулированные когда-то правила летят кувырком. Аксиомы, на которых строилась теорема, перестают быть аксиомами. И лишенное фундамента здание начинает рушиться.

Полюса применения

Известность области

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

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

Изменение требований ТЗ

Для постоянно развивающихся приложений, приложений, где ничего не понятно, что будет в результате разработки, приложений, где предполагается постоянное обновление библиотек, приложений, где пользователям постоянно в голову приходят разные идеи, семь пятниц на неделе и пр. — нужно всяческое тестирование, TDD, Unit-testing, итерационная разработка, способность к постоянному допиливанию и т.п..

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

Использование библиотек

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


пятница, 9 декабря 2011 г.

Stanford Classes Впечатление

Уже давно перевалили за экватор два стенфордских курса, в которых участвую (ML и DB).

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

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

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

Если в наших формах обучения штампуется множество вариантов, чтобы не списали, всячески контролируется процесс обучения, то тут по-другому. Вариантов фактически нет. Чтобы ответить на вопросы quiz'a, достаточно прокрутить их несколько раз и посмотреть на ошибочные. Чтобы сделать упражнения, можно по диагонали просмотреть форум и найти полурешения. Но обучения в таком процессе ноль. И сам курс строится как «Вы пришли к нам из интернета и диплома мы вам не дадим. Но дадим возможность изучить предмет. Пользуйтесь.»

Обучение идет в 3 волны с корректировкой по обратной связи. Сначала лекции. В течение которых задаются вопросы, на которые слушатель отвечает. Отвечает для того, чтобы можно было себя проверить, насколько хорошо усвоен материал (но может вопросы и пропустить). Это где-то 1 простой вопрос на 10-15 минут видео. Следующим этапом является послелекционный Quiz. Серия вопросов, средней сложности. После ответа на каждый из них идет разъяснение, что такой ответ не подходит по такой-то причине. Попробуйте ещё раз. И по большому счету, пробуйте сколько хотите. Далее последней волной являются упражнения. Для закрепления практических навыков. Среди которых есть основные (которые учитываются в курсе) и есть дополнительные (хотите — изучайте, не хотите — ваш выбор).

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


четверг, 8 декабря 2011 г.

Психологические тесты на обобщения

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

К таким тестам относятся многие категории. Это классификация (найти лишнее, разбить на 2 группы), поиск закономерности (продолжите ряд 1,2,4,9,…), подведение двух понятий под общую категорию (объедините одним общим понятием дождь-снег-град) и др..

Попробуем рассмотреть данное явление в контексте распознавания, обучения и понятий ML: что же именно проверяют данные тесты, почему они могут не работать и как их можно оценивать и улучшать?

Предмет тестирования

Рассмотрим тест Амтхауэра. Есть 5 понятий, найти лишнее:

  1. занавес
  2. щит
  3. невод
  4. фильтр
  5. стена

В представлении автора теста данные понятия расположены приблизительно так:

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

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

Какое же решение более оптимальное?

С точки зрения ML наиболее приемлемым решением будет являться прямая 3. Это легко определяется математически: должно быть значительное расстояние от прямой до точек, которые она разделяет. Например среднее квадратичное величин, обратных расстоянию от точек до прямой. Или минимальное расстояние до любой из точек. Тут могут быть варианты решения. Но главная особенность в том, что расстояние должно быть по возможности больше. Чтобы в последующем функция имела большие шансы на выживание. То есть, когда появятся новые примеры, чтобы они удовлетворяли проведенной классификации и функцию не пришлось бы менять.

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

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

Область применения

Почему такой тест может сработать неадекватно?

Первый случай — когда ответ совсем не очевиден. Например для таких понятий:

 

Да, для них можно найти какую-то обобщающую функцию, но вряд ли она будет эффективна или полезна.

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

Ещё один случай: не факт, что сам автор теста придумал эффективное обобщение. Возможно имеется более хорошо работающее решение. Или сравнимое по работоспособности, но не попадающее в ответ.

Оценка и улучшение теста

Один вариант теста может быть лучше другого. И если выяснить, по каким критериям можно сравнивать, то можно подобрать более подходящие тесты.

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

Чтобы тест работал для большинства людей нужно использовать общеизвестные понятия, а не специализированные, или те, которые «очевидноизвестные» и «сдестваузнаваемые» автором. При этом общеизвестные понятия не должны плыть — иметь разный смысл для разных людей.

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