В начале января я с головой окунулась в разработку программного обеспечения, поступив в Hackbright Academy, учебный курс для женщин по программированию в Сан-Франциско.

После шести недель обучения навыкам Python, JavaScript, SQL и многому другому мы, наконец, подошли к «сезону проектов» - месячному разделу курса, в ходе которого мы создаем собственные приложения с нуля. Каждый день я буду публиковать здесь свой прогресс (успехи, неудачи и т. Д.), Чтобы сохранить то, как это было при создании моего приложения. Хотя раньше я возился с небольшими проектами, это будет мое первое серьезное веб-приложение.

Мое приложение называется Book Bingo - это будет интерактивная доска для бинго, в которой каждый квадрат соответствует жанру книги. Когда пользователь читает книгу, которая соответствует одному из этих жанров, он может ввести название и автора в соответствующий квадрат, и приложение подключится к Goodreads API, чтобы получить дополнительную информацию о книге. Когда пользователь читает пять книг подряд, он получает бинго!

В качестве своего MVP я надеюсь достичь следующих целей:

  • Функциональность входа и выхода игрока
  • Создайте одну доску на бэкэнде, к которой будут иметь доступ все игроки
  • Показать доску
  • Разрешить людям редактировать доску и вводить книги
  • Подключитесь к GoodReads API

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

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

День второй. Первым делом сегодня было наладить отношения с моей базой данных. Как только с этим разобрались, я смог вставить тестовые данные в свою базу данных. Поняв, что жесткое кодирование моей платы в HTML - неправильный способ представления данных, я выбросил плату, которую сделал вчера, и начал создавать новую в базе данных. Используя SQLAlchemy и Jinja, я смог получить названия жанров из базы данных и представить их в виде таблицы HTML (после небольшой настройки это будет начало доски, с которой взаимодействует пользователь). Наконец, я связал доски каждого пользователя с их пользовательской страницей.

День третий. Сегодня я реализовал функцию, позволяющую пользователю создать новую доску. Используя HTML-форму и SQLAlchemy, я смог создать маршрут, по которому пользователи могут создавать свою собственную доску, выбирая имя доски и 24 жанра для заполнения ячеек.

День четвертый. Когда доска, наконец, завершена, я весь день работал над вызовом Ajax, который позволял пользователям вводить название своей книги в текстовое поле, нажимать «отправить» и сразу видеть изменения. в DOM (пока я просто хотел, чтобы название книги появилось в соответствующем квадрате). Хотя вызов Ajax работал, я достиг первой большой ошибки проекта, пытаясь заставить доску отображать обратную связь. Поскольку я создал доску с помощью цикла for Jinja, каждый квадрат имел один и тот же атрибут HTML ID, что затрудняло размещение обратной связи в правильном квадрате. Я попытался решить эту проблему, установив в качестве идентификатора переменную Jinja, но jQuery не смог распознать Jinja, а это означало, что я не смог заставить обратную связь работать. В конце концов я решил проблему, установив атрибут данных в HTML, установив его равным переменной Jinja, а затем используя этот атрибут данных в вызове Ajax.

День пятый. После того, как мой звонок Ajax и обратная связь с советом наконец заработали, я потратил сегодня на создание функциональности SQLAlchemy для добавления новых книг в базу данных. Когда я закончил с этим, я начал работать над тем, чтобы сделать обратную связь с советом постоянной. У меня было не так много времени, чтобы погрузиться в это, так что это будет моя главная цель на выходных и в начале следующей недели.

Выходные №1. На выходных я собрал серию запросов SQLAlchemy, чтобы извлечь данные о названии книги и авторе из базы данных и перенести их на свою доску через Jinja. Я столкнулся с ошибкой в ​​своей базе данных, когда обнаружил повторяющуюся запись в своей таблице BoardUser, но беспокоился об ее удалении, если она повлияет на плату, к которой была подключена. Я решил приостановить свой проект, пока не смогу поговорить со своим консультантом.

День шестой. Посоветовавшись со своим консультантом, я решил отбросить запросы SQLAlchemy, которые я сделал на выходных, и объединить их в один гигантский запрос с помощью объединений. После того, как я успешно получил необходимую информацию с помощью объединенного запроса, я приступил к работе, создавая изменения в модели DOM в реальном времени, когда пользователь вводит книгу в базу данных. Используя Jinja, я создал условный оператор, чтобы проверить, есть ли у каждого квадрата связанный заголовок. Если это так, я назначил ему класс под названием «чтение» и использовал CSS, чтобы сделать что-либо с этим классом зеленым. Я также вернулся к функции успешного вызова Ajax, чтобы после успешного получения данных для определенного квадрата использовать jQuery, скрыть форму ввода содержимого для этого квадрата и присвоить ему класс «чтение».

День седьмой. Сегодня я подключил свой проект к Goodreads API. Я настроил вызовы API с помощью метода «поиск по названию», чтобы получить идентификатор Goodreads, а затем использовал его для получения описания с помощью метода «показать по идентификатору». Теперь, когда пользователь вводит название книги в форму, он возвращает описание книги через Ajax. Хотя я еще не использую их, в конечном итоге я планирую реализовать модальные окна Bootstrap в каждом квадрате, и на этом этапе я размещу описания книг рядом с каждым заголовком. Теперь, когда мой проект подключен к Goodreads API, я достиг своего MVP!

День восьмой. Хотя вчера я достиг своего MVP, вчера вечером я обнаружил несколько ошибок: первая и самая важная заключается в том, что мой центральный запрос SQLAlchemy (который заполняет мою доску) ошибочен - он возвращает только квадраты. доска просмотра пользователей заполнена или которую вообще никто не заполнял. Поскольку на этом этапе все пользователи используют одну доску на сервере, это означает, что никто, кроме первого пользователя, не может видеть каждую клетку. Мне удалось решить эту проблему, переработав свой запрос SQLAlchemy с подзапросом. Вторая проблема заключалась в том, что на главной странице каждого пользователя, независимо от того, по какой ссылке он нажимал, они могли видеть только самую последнюю созданную доску. Я заметил, что это проблема с Jinja, и исправил ее соответствующим образом. Наконец, я написал несколько модульных тестов.

День девятый. Что касается моего MVP, мой консультант хотел, чтобы я настроил мой проект таким образом, чтобы несколько пользователей могли взаимодействовать с одной доской, но не видеть отзывы друг друга. Однако в дальнейшем я хочу, чтобы пользователи могли делиться доской, позволяя им играть с друзьями или против них. Чтобы несколько пользователей могли взаимодействовать с одной доской и видеть отзывы друг друга, мне пришлось реконструировать свой центральный запрос SQLAlchemy (тот же, который я исправил на седьмой день). Теперь, вместо того, чтобы объединять таблицы и запрашивать определенные атрибуты, я настроил его таким образом, чтобы было пять запросов, по одному для каждой строки, которые берут все атрибуты из таблицы Square. Используя отношения, я просмотрел результаты запроса, чтобы создать список из пяти списков, и в каждом списке я установил пять словарей (по одному для каждого квадрата, содержащего информацию об идентификаторе квадрата, жанре, игроках, прикрепленных к квадрату, и о том, какие книги эти игроки читали). Когда цикл заработал, я изменил цикл Jinja, который создает мою доску, чтобы использовать списки словарей. К концу дня доска работает так, чтобы несколько пользователей могли играть на одной доске, и каждый пользователь мог видеть, какие книги читали другие пользователи, в то время как на доске все еще отображалась обратная связь, основанная на том, что прочитал пользователь в сеансе.

День десятый. Сегодня я обнаружил небольшую ошибку в своем коде - в словаре для каждого квадрата у меня есть ключ «current_user», значение которого истинно, если авторизованный пользователь прочитал книга в этом квадрате, иначе - False. Однако из-за способа настройки цикла атрибут только подтверждал, что последний пользователь прочитал книгу в этом квадрате. В результате, если текущий пользователь не был последним человеком, прочитавшим книгу в этом квадрате, квадрат теряет класс «прочитал». Чтобы исправить это, я изменил способ настройки атрибута current_user, установив для него по умолчанию значение False и изменив его только на True внутри цикла. После того, как я исправил ошибку, я начал рассматривать остальные функции, которые я хотел бы реализовать, а именно настройку предупреждений, когда пользователь получает бинго, и добавление ссылок для обмена, чтобы игроки могли приглашать друзей поиграть на своей доске.

Выходные №2. В эти выходные я начал работать над настройкой предупреждений, когда игрок получает бинго. Для этого я использовал атрибуты координат x и y каждого квадрата. Я перенес координаты из вызова SQLAlchemy, который настраивает доску, и установил их как атрибуты данных в ячейке в HTML. Я написал функцию JavaScript, которая проверяет пять квадратов с одинаковой координатой x подряд при отправке формы. Для начала я жестко запрограммировал его для проверки квадратов с координатой Y «1», но планирую динамически изменять его в будущем. Однако похоже, что мой синтаксис JavaScript отключен, и я не могу исправить это без второй пары глаз. На третьей неделе я надеюсь отработать этот синтаксис и заставить эту функцию работать.

День одиннадцатый. Посоветовавшись с сотрудниками Hackbright, я понял, что у моей функции оповещения о бинго было несколько проблем. Прежде всего, синтаксис jQuery hasClass () возвращает истину, если какой-либо элемент в списке заданных элементов имеет определенный класс, а не все элементы. Я переписал свой вызов jQuery, чтобы изолировать элементы как с классом чтения, так и с соответствующей координатой y, и проверил, содержит ли список из 5 элементов - если да, функция предупреждения работала должным образом. Во-вторых, я использовал $ («. Submit»). On («click», getBingo) для вызова функции - однако я использовал тот же синтаксис (с другой функцией успеха) для настройки моего вызова Ajax, поэтому Javascript никогда не попадал в функцию предупреждения о бинго. Вместо этого я решил вызвать getBingo () внутри функции успеха Ajax и заставил ее работать! Затем возникла проблема динамического создания оповещения о бинго, а не его жесткого кодирования. У меня возникли проблемы с выделением координат X и Y на доске бинго по отношению к конкретному квадрату, в котором были отправлены данные. Мне нужно было больше узнать об «этом», родителях, братьях и сестрах, и в конце концов я смог ввести координаты в свой вызов Ajax. Как только это сработало правильно, я смог переписать функцию для динамической проверки бинго. Наконец, я написал альтернативные операторы if, чтобы проверять наличие бинго по диагонали по всем направлениям.

День двенадцатый. Этим утром я обнаружил ошибку в моем коде для диагональных предупреждений о бинго - когда все необходимые квадраты имели класс «читать», каждый раз при вводе новой книги где угодно на доске, "Бинго!" подошло предупреждение. Изучив его, я понял, что это было из-за того, как я написал логику - после того, как эти квадраты были «прочитаны», логика для бинго всегда оставалась верной, даже если квадрат, с которым вы сейчас имеете дело, не был одним из их. Чтобы исправить это, мне пришлось реорганизовать код, чтобы иметь дело с координатами X и Y, входящими в этот конкретный квадрат. Как только это было исправлено, я создал новый маршрут для ссылки общего доступа на основе идентификатора доски. Глядя на доску, пользователи могут скопировать соответствующий URL-адрес для совместного использования и отправить его другу, который - при нажатии на него - получит идентификатор доски в своем сеансе. После регистрации или входа в систему этот пользователь добавляется на доску в базе данных, и сайт перенаправляется на соответствующую доску. После того, как общие ссылки заработали, я реорганизовал свой файл сервера, чтобы подготовиться к написанию модульных тестов.

День тринадцатый. Поскольку мой проект в настоящее время находится в хорошем состоянии с точки зрения функциональности, я решил уделить время написанию модульных тестов. Я включил ранее написанные модульные тесты в новый файл, а затем написал дополнительные тесты. К концу дня мой проект был покрыт 80%.

День четырнадцатый. Сегодня утром я изучал тестирование Jasmine для JavaScript. Однако, поскольку ни одна из моих функций JavaScript ничего не возвращает явно (скорее, они меняют DOM), я понял, что это не будет для меня эффективным методом тестирования. Решив отложить модульное тестирование JavaScript на другой день, я внедрил в свой проект модальные окна Bootstrap. До этого момента, когда пользователь читал книгу, информация об этом пользователе и этой книге просто добавлялась в div под формой в каждом квадрате - однако это было крайне неэлегантно. Более того, я получаю описание книги из Goodreads API, и если я хочу использовать его для каждой книги, мне нужен лучший способ отображения всего. Помещая модальное окно внутри каждого квадрата, я могу получить свежий холст, на котором можно отображать эту информацию, не запутывая доску. У меня возникли проблемы с тем, чтобы модальные кнопки работали для каждого отдельного квадрата, но к концу дня у меня были рабочие модальные окна!

День пятнадцатый. Теперь, когда у меня есть рабочие модальные окна, я хочу, наконец, перенести на доску описания книг, которые я получаю от Goodreads API, чтобы я мог их отображать (идея заключается в том, что пользователи могут увидеть описания книг, которые прочитали их друзья). Я добавил вызовы API к запросу SQLAlchemy, который собирает информацию о каждой книге, и быстро понял, что этот метод получения информации полностью снижает эффективность моей работы во время выполнения. Чтобы решить эту проблему, мне пришлось изменить таблицу «Книги» моей базы данных, добавив столбец «Описание» (вместе со столбцом URL-адреса Goodreads, пока я его изменял). Я отбросил свою базу данных и добавил необходимые вызовы API в функцию, которая добавляет книги в базу данных. К сожалению, из-за расписания Хэкбрайта на пятницу это было все, что у меня было сегодня на это время. На выходных я надеюсь протестировать его и убедиться, что получаю правильную информацию в базе данных и из нее.

Выходные №3. На выходных я добавил вызовы API к функции, которая добавляет книги в базу данных. Однако я заметил, что в качестве побочного эффекта от Goodreads API, возвращающего XML, HTML-теги, такие как «‹br›» и «‹b›», отображались как часть строк описания, а не отображались как HTML во внешнем интерфейсе. . Чтобы решить эту проблему, я использовал регулярные выражения, чтобы убрать что-либо между этими тегами из строки.

День шестнадцатый. Сегодня утром первым делом в моем списке дел был рефакторинг кода для диагональных предупреждений бинго, чтобы сделать его менее повторяющимся. Как только это было сделано, я приступил к поиску способа сделать мои предупреждения «бинго» менее навязчивыми. Я нашел плагин jQuery под названием jQuery-Confirm, который улучшает внешний вид предупреждений, и реализовал его. Наконец, я начал добавлять больше элементов Bootstrap, таких как jumbotron на мою домашнюю страницу, и настраивать мои модальные кнопки.

День семнадцатый. Чтобы получить больше впечатлений от интерфейса, я решил добавить визуализацию данных на каждую страницу доски, чтобы отображать, сколько книг прочитал каждый пользователь на доске. Запрос SQLAlchemy, необходимый для получения желаемой информации, оказался сложнее, чем я ожидал, поэтому я потратил немало времени на его точную настройку. Когда мой запрос, наконец, возвращал желаемые результаты (список кортежей с именем каждого игрока и сколько книг они прочитали на этой доске), я начал изучать несколько подключаемых модулей визуализации данных, включая Chart.js и Plotly. Прочитав документацию для обоих, я решил, что Plotly был лучшим выбором для моего проекта, и внедрил график «Статистика доски» на каждой странице.

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

День девятнадцатый. Сегодня я с головой погрузился в тестирование Selenium. Мне пришлось преодолеть ряд препятствий, прежде чем я смог заставить Selenium работать: во-первых, Selenium не работает на виртуальной машине Hackbright, поэтому мне пришлось переключиться на свой локальный терминал. Затем я узнал, что Selenium совместим только с Firefox 47.0.1, поэтому мне пришлось соответственно понизить версию моего Firefox. Наконец, мне пришлось установить GeckoDriver в соответствующий путь к файлу. К тому времени, как все было сказано и сделано, у меня было только время реализовать несколько тестов Selenium, но я все еще был взволнован, увидев их работу - наблюдать, как Selenium WebDriver работает сам по себе, очень приятно!

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

Выходные №4. Выполнив свои функции, я взял выходные, чтобы обсудить темы по информатике и начать мозговой штурм дизайнерских идей. Я реализовал несколько функций Bootstrap и поискал вдохновение для дизайна в Интернете.

День двадцать первый. Сегодня был первый из двух дней, разрешенных для «приведения в порядок» наших приложений. Первое, что я сделал, это выбрал цветовую схему - я знал, что хочу объединить темно-бордовый и ярко-зеленый, и выбрал другие цвета на основе этого. Затем я отформатировал домашнюю страницу пользователя. Сначала я разработал векторную графику в форме книги и планировал расположить имя пользователя с одной стороны, а доски - с другой, но после реализации идеи решил, что мне это не нравится - особенно потому, что было трудно масштабировать графика с адаптивными функциями Bootstrap. Отказавшись от этой идеи, я остановился на простом зелено-белом фоне с изображением книги. Я искал в Hackbright, пока не нашел книгу, которая не была о Python, сделал снимок и использовал Adobe Illustrator, чтобы наклеить его на свое фоновое изображение. С этим дизайном я использовал аналогичный зелено-белый фон с изображением книги для страницы New Board. Самым сложным аспектом дизайна была попытка манипулировать CSS, чтобы мои фоновые изображения хорошо масштабировались с окном браузера. Наконец, я изменил шрифты и цвета на странице доски бинго, чтобы объединить все воедино.

День двадцать второй. Сегодня последний день работы над нашими приложениями - завтра вечер демонстрации! Хотя сегодня якобы был вторым днем ​​«приукрашивания» наших приложений, на самом деле большую часть дня ушел на создание моего скринкаста для Demo Night, когда мы представляем наши приложения компаниям-партнерам. Я записал видео с экрана с помощью RecordIt, а затем отредактировал его в соответствии с моей запланированной речью с помощью Adobe Premiere. К концу дня мое приложение и скринкаст были готовы к работе!

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

Хотите увидеть конечный продукт? Посетите: http://book-bingo.herokuapp.com/ или посмотрите код на: https://github.com/jessapp/book-bingo

Джессика Аппельбаум - инженер-программист, живет в Сан-Франциско, Калифорния. Свяжитесь с ней здесь!