Tom Adler’s blog

test-driven development

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

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

я помню, как в описании TDD я читал нечто вроде: «сначала мы создаём набор тестов, а потом пишем код, чтобы он проходил эти тесты». В этом описании слишком много планирования, на мой вкус. Начиная программировать, я часто слабо представляю даже структуру кода, не говоря уже об именах объектов и методов. Как в такой ситуации можно писать тест? А вот когда несколько строчек уже есть, и понятно, как что называется, тогда вместо интерактивной проверки состояния программы можно и тест написать. Один тест, который проверит то, что важно прямо сейчас

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

если же именно это и является правильным способом применять TDD, то окажется, что очень многие тесты в нокии написаны совершенно бездумно. Например, если функция вызывается с одним параметром-объектом, который создан литералом прямо внутри вызова, типа do({…}), то зачем в тесте проверять, что внутрь придёт именно такой объект? Зачем проверять, что субпроцедуры вызваны, если функция линейная? Неудивительно, что такие тесты не вызывают желания заниматься TDD

,

кнопка, точно кнопка

сегодня с некоторым удивлением обнаружил в разделе «the button element» спеки html5 такие слова:

The missing value default is the Submit Button state.

значит, если вам нужна просто кнопка, которая не отсылает форму на сервер, недостаточно кода <button>кнопка</button>. Для пущей надёжности и тех, кто с первого раза не понял, нужно писать вот так:

<button type="button">кнопка</button>

тогда каждый дурак поймёт, что это просто кнопка. А ведь при Путине такого не было, тогда наоборот было, верно я помню?

,

JSONP, статика и CDN

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

но что, если у вас на сервере нету скриптов? Что, если вы отдаёте статические файлы через CDN и не собираетесь отказываться от быстрой доставки данных в браузер пользователя и сниженной нагрузки на свои сервера? С некоторыми предпосылками решение такой проблемы довольно очевидно, хотя и вступает в противоречие с привычным шаблоном использованием JSONP.

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

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

JSON.request({
    uri: 'http://example.com/static.jsonp',
    notify: true
});

JSON.notify(
    'http://example.com/static.jsonp',
    {crossDomain: true}
);

пробел против фиксированных элементов

ни для кого не сюрприз, что пробел — самая большая и потому самая удобная кнопка на клавиатуре. Поэтому её довольно часто пытаются приспособить для действий, отличных от ввода символа пробела. В частности, любой «настольный» браузер при нажатии этой кнопки прокручивает страницу на один экран вниз. Этакий удобный Page Down. (А Shift-Space прокручивает страницу на экран вверх, аналогично Page Up.)

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

честно говоря, этот пост обязан своим появлением совпадению. Совпали моё настроение побрюзжать и «плавающая панель» фейсбука. Поскольку для неё задан стиль position: fixed, она остаётся видимой наверху страницы независимо от прокрутки, и закрывает пару строчек содержания. Поэтому, если дочитать видимый на экране текст и нажать пробел, на следующем экране продолжение у текста будет неожиданным. Ещё бы, две строчки выпали.

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

перехват f11

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

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

а малограмотных юзеров можно приучать к этой кнопке так же, как учат отправлять сообщения по Ctrl+Enter: подсказкой рядом с кнопкой на экране. Ведь наверняка про полноэкранный режим знает ещё в 10 раз меньше людей, чем про возможность поиска по Ctrl+F.

для пуристов можно добавить, что другие способы переключения в полноэкранный режим тоже можно отслеживать как изменение размеров окна. Мы ведь можем сравнить высоту экрана с высотой viewport: если они совпадают¹, значит, режим включен, иначе выключен. Это вряд ли сработает для двух подключённых мониторов, которые настроены в ОС как расположенные один над другим, но вот это уже частный случай.

и, пожалуй, стоит упомянуть Opera Presentation Mode, поскольку задача у него очень близкая

¹ почему-то Firefox делает высоту viewport на один пиксель меньше, чем высота экрана, но это легко обходится