Это была очередная пятница в тихом, уютном баре с лучшими друзьями… Разговор шел как обычно: новости, работа, шутки и опять по кругу. В поисках темы для разговора, потягивая из пивных кружек, почему-то вспомнили о стихах :) И тут каждый стал припоминать, что он еще помнит с тех далеких школьных лет. Если спотыкался, остальные подсказывали, ежели кто помнил, было довольно весело и интересно. Возвращаясь домой в тот вечер, я подумал: а что если сделать простое веб-приложение, чтобы каждый мог вспомнить эти прекрасные произведения русской поэтической мысли? Дизайн приложения уже крутился в голове, и я засел за разработку… 
 Необходимо написать веб-приложение, где пользователю случайным образом выпадает стихотворение, которое он должен закончить, дописывая "пропущенные" слова по мере повествования. В конце пользователю должен быть отображен результат и возможность открыть другое стихотворение. Дополнительные требования к приложению: Для оформления специально были проштудированы старые издания стихов, чтобы почерпнуть стилистику оформления печатных изданий того времени. Хотелось чего-то печатного, ощущения "бумаги" и при этом простого. Нынешнее увлечение Flat-дизайном делает вещи проще, тем более для программиста, ведь он не дизайнер. Имхо, получилось сносно: 
 Хорошему проекту нужно хорошее имя. Проверив несколько доменов, я быстро нашел подходящее имя для проекта — literator.io. Это только потом я узнал, сколько стоит домен в зоне .io, но менять что-то уже было поздно, "искусство требует жертв". Что может радовать программиста в работе больше, чем возможность писать хороший код и не быть связанным дедлайнами? Но порядок все равно нужен, и я замутил небольшой Kanban в Trello. Люблю порядок. Да, заметил, что и на GitHub’е теперь можно создавать борды. Возможно, перееду туда. Выбор фреймворка для построения приложения пал на AngularJS, т.к. несколько проектов с основного места работы использовали его. Дело было год назад, Angular 2 тогда был еще в глубокой жопе бете, а React был мне незнаком. Так же хотелось отточить свои навыки в AngularJS, чтобы не потерять сноровку, т.к. по работе приходилось больше писать на ванильном JS под Titanium SDK, а это совсем другая область. Поразмыслив над возможной архитектурой и прикинув различные варианты, я пришел к следующей структуре: 
 Как видите, выделяются две сущности: авторы и стихи. Каждая из сущностей описывается метаданными, файлы которых располагаются в тех же директориях. Стихи (verses) дополнительно имеют файл content.txt, где как раз и хранится стих.  Отдельно выделяется файл structure.json. Если помните, одно из условий задачи было сделать приложение, для которого не нужен будет бекенд. А раз нет бекенда, то мы не можем перебирать доступные директории, чтобы узнать структуру наших данных. Как раз для этого и нужен файл structure.json, который хранит всю структуру и метаданные. Чтобы каждый раз не изменять этот файл вручную, была написана Node-утилита, которая проходится по всем доступным директориям и собирает метаданные (не зря же мы их там разложили, к тому же это удобно). Как говорится: "Разделяй и властвуй". Хороший разработчик не будет хранить данные (хоть и статические) вместе с исходным кодом в том же репозитории, поэтому для стихов был создан отдельный репозиторий. Так же это позволит использовать всю мощь pull-реквестов для того, чтобы желающие могли добавить новые стихи и новых авторов. Данный репозиторий подключается к основному репозиторию через Git Submodules, что дает дополнительный контроль за тем, какая ревизия данных сейчас используется. Оставалось изменить таск grunt build, чтобы всё собиралось и копировалось по своим местам. Отдельно хотел остановиться на том, как было реализовано автодополнение слов и вообще разбитие стиха на фрагменты, которые нужно заполнить пользователю. Стоял выбор между алгоритмическим выбором блоков и явным указанием этих блоков в самом стихе. Еще хотелось сделать возможность выбора сложности в будущем, поэтому блоки должны были выбираться по-разному. Я выбрал второе — явное указание этих блоков в самом стихе. Это требует предподготовки текста стиха, но позволяет получить лучший результат, т.к. позволяет подобрать [субъективно] наиболее удачные фрагменты, которые будут соответствовать рифме/течению стихотворения и смыслу повествования. Так же тот, кто подготавливает стих, может заранее оценить на сколько сложно/просто будет решить конкретный фрагмент. Как видите, фрагменты заключены в фигурные скобки. Вложенность необходима для указания фрагментов разной сложности. Скобки "раскрываются" от внутренних к наружным, таким образом "легкому" уровню сложности соответствуют самые внутренние скобки в конкретном выделенном фрагменте. Фрагмент вида {годы{}} соответсвует тому, что он будет использован только для "средней" сложности и пропущен на "легкой", т.к. вложенные скобки ничего не содержат. Таким образом можно добавить любую сложность, в принципе, но на текущий момент в разметке используются только две, а в приложении пока доступна только "легкая". При выборе стихотворения, происходит его нормализация для выбранной сложности и лишние скобки удаляются, после чего оно разбивается на фрагменты. Если интересно, код ниже. Пытался сделать нормализацию регуляркой, но так и не смог собрать рабочую, хотя, думаю это возможно (должно работать для любой вложенности, не только для двух). Отдельное внимание было уделено юзабилити и совместимости с мобильными платформами, ведь как вы знаете, пользовательский опыт там существенно отличается от десктопного. К тому же, мобильный веб-серфинг уже обогнал десктопный. Определенную боль принесла оптимизация под iOS Safari, в основном из-за того, что программно нельзя поставить фокус на поле ввода, если пользователь не совершил никаких touch-действий. Поэтому там пришлось добавить специальную подсказку, чтобы пользователь тапнул в любое место на экране — только тогда мы можем установить фокус на нужном элементе, что немного портит юзабилити. Если кто-то знает, как решить эту проблему — пишите! Моя последняя попытка здесь https://jsfiddle.net/6tfrh7qn/5/ (открывайте в iPhone Simulator). Еще не нашел как отстайлить каретку. 
 И всё равно там какой-то баг с курсором, который может не отображаться после фокуса на поле. В процессе разработки регулярно проводился User Testing (в основном на родных и близких) чтобы выявить ошибки в UI, UX (пользовательский опыт) и вообще проверить корректность подачи идеи. Тесты дали очень хорошие плоды, позволив существенно улучшить UX. На одном из тестов выяснилось, что пользователь думал, что в месте останова повествования нужно писать всё, что помнишь дальше. Тогда первая подсказка была изменена с "Начните печатать и закончите стихотворение" на "Начните печатать следующее слово". Также выяснилось, что пользователь не понимал, правильно ли он печатает и сколько нужно печатать, потому что в основном смотрит на клавиатуру. Тогда я добавил звук, проигрываемый при правильном завершении фрагмента. Получилось достаточно интуитивно. В общем, очень полезная практика, не пренебрегайте юзер-тестами! Также весь код покрыт Unit-тестами и E2E-тестами, не в каждом проекте удается выкроить на это время. Писать их было одно удовольствие, местами разработка шла по TDD. Да, E2E тесты на Protractor могут сфейлиться, если окно браузера, запускаемого тестом, на заднем плане или невидимо. Если кто знает, как это исправить, просьба сообщить. Веб-приложение: http://literator.io
Репозиторий приложения: https://github.com/bobrosoft/literator.io
Репозиторий стихов: https://github.com/bobrosoft/literator.io-verses Разработка шла неспешно, и прошло уже более года с момента её старта. Хоть и основная часть была завершена довольно быстро, потребовалось время, чтобы всё отполировать и закончить — принцип Парето в действии :) Иногда пропадало желание продолжать, т.к. в голову приходили совершенно новые идеи, но я сделал усилие, а то этот гештальт не давал бы покоя. Думаю, что для начала добавил все стихи, которые должны быть известны большинству из нас. Старался пока не брать длинные стихи (хотя есть "Бородино"), чтобы не утомлять пользователя. Если незаслуженно пропустил что-то, напишите в комментариях, добавлю. Идеи развития проекта (в порядке важности): Спасибо за внимание! Надеюсь, кому-то этот проект покажется интересным и принесет положительные эмоции :) UPD: кому интересно дальнейшее развитие проекта, вступайте в группу https://vk.com/literatorio или https://www.facebook.com/LiteratorioApp/ чтобы не пропустить анонс обновлений. Full Stack Web Developer