Мотивация


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

Если интересно, что с этим может поделать отдельный человек — добро пожаловать под кат.

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

Итак, что может сделать отдельный customer, чтобы усложнить задачу по формированию собственного предсказуемого поведения? Для меня ответ заключается в следующей фразе — чтобы научиться чем-то управлять, необходимо научиться это измерять.

Но что может измерять человек сам у себя и как это анализировать? Решение придумано довольно давно — это ведение личного дневника (своя/моя little data) и последующий анализ зафиксированных событий.

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

Итак, какими свойствами может обладать идеальный дневник:
  • Заведение данных и их быстрая (в пределе, автоматическая) классификация, по разным видам объектов, таких как, мысли, задачи, напоминания, контакты, сон, заметки и т.д. Ведение связей между объектами;
  • Загрузка данных из внешних источников (соц.сетей, банковских счетов, трекеров физ.активности);
  • Автоматическое построение аналитики, по разным срезам информации;
  • Выдача подсказок по текущим действиям (задача с высоким приоритетом, дни рождения и т.д. и т.п.);
  • Возможность настройки алгоритмов, по индивидуальной обработке объектов;
  • Система должна предоставлять выбор, какая информация доступна для публикация во внешнюю сеть, а какая остается персональной (реализация должна обеспечивать честность в этом отношении), данные во внешней сети также классифицируются и раскладываются на составляющие;
  • В пределе любая информация, с которой сталкивается человек, и любая информация, которая генерится данным человеком должна классифицироваться и укладываться в такой дневник.

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



Задача


Изначально я ставил перед собой следующие цели:
  1. Создание любых видов объектов без разработки;
  2. Вывод одинаковых объектов на отдельной странице с отображением в табличном виде, а также с возможностью перехода к отдельному объекту и отображения\ведения в виде карточки;
  3. Возможность установления связей между объектами;
  4. Настройка статусов и категорий для объектов;
  5. Ведение аналитики\напоминалок\прогнозирования.

Результаты


Получилось:
  • Создание новых объектов;
  • Создание статусных схем, привязываемых к любым видам объектов;
  • Есть возможность создавать ссылки между объектами, ссылки отображаются в отдельной вкладке. По сути ссылки решают задачу наследования и являются связями между любыми объектами;
  • Гиперссылки на объекты — возможно задавать прямую ссылку на объект;
  • Для задач есть возможность создания отдельных папок для удобства обработки.

Проблемы:
  • Нет аналитики;
  • Нет каскадного удаления дочерних объектов;
  • Нет возможности поиска объектов;
  • Нет возможности на одной странице обрабатывать несколько объектов;
  • Сложность создания новых видов объектов (описание объекта занимает порядка получаса, даже у меня как автора)
  • Более менее понятная архитектура превратилась в набор хаков

Решение


Disclaimer! Автор не является профессиональным программистом и специалистом в области разработки на python\js, а всего лишь любителем, поэтому идеи по правильной организации архитектуры и используемым технологиям приветствуются и я буду очень благодарен за данные советы.

Код на github

Используемый инструментарий


Backend:
  • Python 3.2.5 — Серверная часть
  • SQLite 3.5.1 — База данных

Frontend:
  • Bootstrap 3.3.6 — Отображение данных
  • JQuery 2.2.0 — Логика
  • TinyMCE 4.3.2 — Редактор текста. Дополнительно использовался плагин syntaxhighlighter, для форматирования кода.
  • Datatables 1.10.10 — Отображение данных в табличной форме.

Архитектура решения


image

Общее описание архитектуры


  1. На Python написан сервис, который крутится на localhost и выполняет обработку запросов от html-страниц.
  2. Объекты представляют собой html-страницы с определенной разметкой, в которой указываются названия полей, соответствуют полям в базе данных (не используется никаких ORM решений, обработка осуществляется своим велосипедом)
  3. Общение с сервером происходит через json-сообщения.
  4. Все объекты с сервера загружаются при первоначальной загрузке страницы, в дальнейшем происходит обмен только дельтой.
  5. Есть встроенные объекты, это статусы и отношения, остальные объекты описываются отдельно (см. ниже)

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

Frontend:
  • Main.js — Точка входа для обработки событий frontend. Производится инициализация начальных данных, обработка событий с html-страницы, вызов других объектов для работы.
  • datatype.js — Внутреннее преобразования данных в необходимый формат для обработки в зависимости от сценария.
  • card.js — Обработка карточки объекта, отображение данных карточки для редактирования, просмотра, связей, сохранение данных.
  • main_view.js — Управление отображением карточки\таблицы на странице
  • myajax.js — Обертка для ajax-запроса
  • mydatatables.js — Обертка для работы с datatables.net.
  • mytinymce.js — Обертка для работы с TinyMCE
  • %ObjectName% — Параметры, по каждому виду объекта.
  • all_relations.js — Все возможные виды объектов, доступных при отображении отношений.
  • object_state.js — Класс для обработки вида объекта
  • rel.js — Обработка отношений между объектами.
  • requester.js — Преобразование данных в формат для передачи на сервер.
  • settings.js — Константы.

Backend:
  1. server.py — Обработка запросов.
  2. json2sql.py — Преобразование json-запроса с frontend в sql-запрос для БД
  3. dbserver.py — Выполнение sql-запроса.
  4. settings.py — Параметры.
  5. object2db.py — Параметры видов объекта на сервере.
  6. actionfile.py — Создание директорий для задач.


Схема базы данных:
  • %object_name% — Отдельная таблица для каждого создаваемого объекта.
  • sys_status — Возможные статусы, сгруппированные по статусным схемам.
  • Sys_rel2obj_items — Данные по связям между объектами
  • Sys_rel_object2object — Настройка соответствия отношений между объектами
  • object_type — Описание типов
  • Sys_rel — Описание отношений


Примеры JSON-сообщений:
  • Получить статусы по объекту — {“object”: “status”, “action”:”select”, “items”:[{“id”:1,”msg”:{“fields”: [{“column”:”id”, “op”:”>=”, “value”:”0?}]}}]}
  • Получить отношения по объекту — {“object”: “rel_items”, “action”:”select”, “items”:[{“id”:1,”msg”:{“fields”: [{“column”:”obj1_type”, “op”:”=”, “value”:”project”},{“column”:”id1?, “op”:”=”, “value”:”22?}]}}]}
  • Получить возможные отношения объектов — {“object”: “sys_rel_object2object”, “action”:”select”, “items”:[{“id”:1,”msg”:{“fields”: [{“column”:”id”, “op”:”>=”, “value”:”0?}]}}]}
  • Получить все объекты — {“object”: “project”, “action”:”select”, “items”:[{“id”:1,”msg”:{“fields”: [{“column”:”id”, “op”:”>=”, “value”:”0?}]}}]}
  • Создать объект — {“object”:”project”, “action”:”insert”, “items”:[{“id”:0,”msg”:{“fields”:{ “title”:”123?,”note”:”123” }}}]}
  • Изменить объект — {“object”:”project”,”action”:”update”,”items”:[{“id”:0, “msg”:{“fields_set”:{“title”:”1234?,”note”:”123”}, “fields_where”:{“id”:”22?}}}]}


Где:
  • Object – тип объекта (например, проект, задача и т.д.)
  • Action – тип действия (создание, удаление, измение, удаление, получить)
  • Items – в рамках одного сообщения, можно запрашивать несколько элементов, например, делать несколько insert.
  • Msg – сообщение в рамках одного пакета
  • Fields – поля по данному объекту


Некоторые из созданных объектов:
  • Project– ведение проектов.
  • Task– ведение задач
  • Question– ведение вопросов
  • Think– ведение мыслей, идей и т.д.
  • Timing– контроль времени ()
  • Contact– ведение контактов
  • Diary– ведение личного дневника
  • Snippet– snippet

Алгоритм создания нового объекта


  1. Создать таблицу в БД
  2. Создать файл %object_name%.html
  3. Создать файл %object_name%.js
  4. Описать объект в файле object2db.py
  5. При необходимости добавления статуса заполнить данные в таблицах (sys_status)
  6. При необходимости создания новых отношений заполнить данные в таблицах(sys_rel_object2object)

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

Планы на будущее для версии 2.0


Идеал – работа с любыми объектами в рамках одного окна, минимум действий с помощью мышки. Максимум перевести на описание в командной строке.

Идеи:

  • Редактор объектов. — Создание объектов, без необходимости ручного создания html-страниц, наличия отдельного js-файла для объекта и отдельной настройке на python.
  • Создание статусов.
  • Создание\настройка отношений.
  • Отображение на одной странице множества объектов. — В настоящий момент архитектура построена таким образом, что на одной странице возможно отображение только одного вида объекта (не считая ссылок на другие объекты).
  • Командная строка — Командная строка для сокращения кол-ва действий для выполнения операций.
  • Например, находясь на объекте «Проект» в командной строке набирается «Задача» и происходит автоматическое создание объекта «Задача» со ссылкой на данный проект. Т.к. в настоящий момент нужно перейти на вкладку
  • Шифрование. — Добавить шифрование БД.
  • Аналитика — Возможность базовой аналитики по объектам, с отображением кол-ва по статусам, важности и т.д.
  • Добавление объекта сроки(даты) — Отдельный объект, который можно добавлять в любой объект с возможностью добавления стоков
  • Активности — Возможность отработки определенных действий
  • Проверка на дублирования — При создании инстанции объекта проверка на дублирование
  • Обязательность полей — Определение полей, обязательных для заполнения.

Заключение


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

Данной системой пользуюсь, порядка 3 месяцев, попутно исправляя ошибки, полёт ± ровный.

Спасибо за уделённое время.
Поделиться с друзьями
-->

Комментарии (18)


  1. hlogeon
    27.07.2016 16:44
    +7

    Добро пожаловать на Хабру, конечно, но лично у меня после всего прочитанного в голове нет ни одного вопроса кроме: «И чё?». Может я устал, конечно, но вот хоть убей никакой ценности не вижу.


    1. J_K
      27.07.2016 22:36
      +1

      Ценность, видимо, в идее.


    1. istulenkov
      27.07.2016 22:57
      +2

      Cкорее всего ценность вижу только я, как автор, потративший n-ое кол-во времени на реализацию. Основная идея в том, чтобы показать, как можно довольно просто сделать свой личный todo-менеджер, с возможностью расширения.

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


      1. cry_san
        28.07.2016 05:43

        как можно довольно просто сделать свой личный todo-менеджер

        Просто не получилось. Но есть куда еще упрощать.


  1. bromzh
    28.07.2016 04:09
    +14

    всё_очень_плохо.jpg


    Архитектуры в проекте нет, всё выглядит как набор файлов, в которых всё сильно захардкожено и которые как-то работают.


    Бэкенд


    • Нет никакой обработки исключений. Любой невалидный json сломает сервер. Любой json, в котором не окажется нужного ключа, сломает сервер. Любая ошибка от БД сломает сервер.
    • Непосредственно сам сервер очень странный. Почему BaseHTTPRequestHandler? Можно было либо сделать WSGI-приложение (чтобы можно было запускать на весьма продуктивных wsgi-серверах), либо взять питон посвежее (>3.4) и задействовать asyncio (чтобы было асинхронно). Первый вариант для данной задачи предпочтительнее. Плюс, довольно странная концепция посылать на сервер запросы только на 1 endpoint на манер некого QueryLanguage, причём, без всякой валидации оного. Есть же JsonSchema. Да и REST в данном случае подошёл бы лучше.
    • Работа с БД. Есть прекрасный проект sqlalchemy, состоящая из 2-х частей. Core-часть представляет некий обобщённый интерфейс для работы с БД. Позволяет абстрагироваться от конкретной БД и писать запросы на неком DSL, которые потом трансформируются в SQL. Ещё есть ORM-часть, если вдруг понадобится. Так же для неё есть дополнительные инструменты: миграции, сериализация моделей, полнотекстовый поиск, и т.д. А что у вас? Всё завязано только на sqlite, все имена таблиц жёстко прописаны и изменить их не сломав приложение будет очень трудно. Миграций нет, так что изменить схемы будет не просто. Генерация SQL из JSON выглядит очень подозрительно и хрупко. Особенно удручает, что тестов нет. Плюс, как я понял, модели строятся только на фронте, а связанные объекты запрашиваются отдельным запросом (а транзакций нет). Если так, то консистентность данных никак не гарантируется, что очень печально.
    • Очень странно, что бэкенд совсем не знает о данных, с которыми работает. Из-за этого нет ни валидации данных на стороне сервера, ни возможности хоть как-то кастомизировать (де)сериализацию данных.
    • Если заглянуть в код сервера, то можно увидеть, что при каждом запросе создаётся новый экземпляр класса для работы с БД, хотя достаточно было создать его только 1 раз.
    • В самом классе для работы с БД новое соединение с базой создаётся при каждом новом запросе, хотя его тоже достаточно создать 1 раз.
    • Сам код тоже плох: очень много elif, повсюду небезопасное получение ключа у словарей (надо через .get()), кодстайл тоже очень хромает.

    Фронтенд


    • Всё в глобальной области видимости.
    • Нет проверки, все ли необходимые js-файлы загрузились и все ли объекты доступны.
    • Нет никакой структуры приложения. Бизнес-логика вперемешку с логикой отображения. Где-то в селекторы передаётся строка из настроек, где-то просто так.
    • JSON генерируется вручную, путём конкатенации строк… Ну есть же штатный JSON.stringify!
    • Зачем столько NaN совсем не по делу? Нужно либо инициализировать null-ами (или пустыми объектами), либо оставлять undefined.
    • Повсюду функции-конструкторы без аргументов. Попытка сделать всё в ООП-стиле? Но при этом, прототипы не используются нигде. Зачем так? Нужен просто объект — создавай через синтаксис со скобками ({ foo: function (a, b) {...} }). this будет работать и так.
    • Непонятные обёртки для ajax, console, etc.
    • Трэш в codestyle
    • Куча html-страниц с кучей copy-paste. Если потребуется поменять шапку, придётся лезть в каждый html-файл. Есть же шаблонизаторы/препроцессоры.

    Как же всё это улучшить?
    Всё приложение по-сути просто интерфейс к БД со стандарным набором CRUD-методов. Незачем придумывать велосипеды, намного быстрее взять что-то готовое. REST API в данном случае подойдёт очень хорошо.
    Лично я сделал бы так:


    Вариант №1. Описать схему данных в swagger'е. Сваггер умеет по схеме генерировать много чего полезного. Например, html-формы и даже контроллеры для методов REST. Вполне подойдёт, для быстрого старта тем более. Потом уже можно будет допиливать бэк и фронт.
    Вариант №2. Написать всё самому, используя готовые фреймворки.


    Вместо непонятного json-query-language использовать REST-подход. На клиент отправлять не просто данные из БД, а сериализованные модели с учётом связей.
    На Никаких имён таблиц и столбцов на клиенте! Доставать данные из БД, строить из них модели, учитывая отношения и серилизовать их должен не клиент, а сервер. Фронт должен уметь лишь отображать полученные данные и, используя формы, отправлять данные на сервер.


    Бэкенд
    Взять Flask в качестве микро web-framework. Для работы с БД использовать SQLAlchemy. Добавить Flask-migration для удобных миграций. Для REST API взять Flask-Restless. Всё это прекрасно умеет работать совместно. Добавить на серверную сторону валидацию данных, грамотную обработку ошибок, и гибкий конфиг.


    Фронтенд
    Вместо кучи html-файлов и хрупким js-кодом, написать SPA. Взять какой-нибудь фреймворк (angular/angular2/backbone/ember), добавить к нему расширения для работы с REST, нормальный wysiwyg-редактор и Grid для отображения таблиц.
    Само приложение структурировать по-человечески: отдельно написать сервисный слой, где будет происходить общение с сервером через ajax, отдельно реализовать view-слой, где полученные от сервисов данные будут отображаться в нужном виде.


    Добавить в проект таск-раннер или сборщик (gulp/webpack).
    В идеале, стоит использовать ES6 и Babel (или TypeScript), чтобы писать нормальный современный JS-код. Добавить загрузчик модулей (requirejs, system.js, webpack) и явно импортировать в js-файлы нужные зависимости, чтобы быть уверенным, что все зависимости загрузились.


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


    1. istulenkov
      28.07.2016 08:47

      Большое спасибо подробный технический комментарий! Буду изучать.


      1. bromzh
        28.07.2016 10:22

        Можно сперва посмотреть в сторону свагера. Вот тут есть демка его редактора, там сверху есть 2 пункта меню: "сгенерировать сервер" и "сгенерировать клиент". Можно посмотреть, что он нагенерирует и взять что-то за основу. Ещё больше инструментов тут.
        Ещё для REST API на питоне есть, например, Eve (кстати, оно тоже умеет со сваггером работать).


    1. elliadan
      28.07.2016 17:10

      Простите, не совсем «в тему» ответ, но я вам хочу аплодировать за то, что вы вот так изучили что-то внезапно-новое и чужое, и подробно расписали-разложили всё по полочкам. Очень впечатлило. Такие комментарии к подобным статьям — оооочень большая редкость.


    1. Dmitriy_ua
      29.07.2016 13:29

      Очень основательный комментарий, спасибо!
      Скажите, как изменилась бы предложенная вами схема с использованием MVC в ASP.NET?


  1. djinninia
    28.07.2016 09:11

    Идея мне нравится.

    ведение личного дневника и последующий анализ зафиксированных событий

    Анализ событий можно развить в систему рекомендаций. Например, в течение определённого периода времени вы интересовались какой-то темой. Потом забыли про это. Система напоминает вам про это.


    1. hlogeon
      28.07.2016 11:38

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


      1. istulenkov
        29.07.2016 07:47

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

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

        По реализации я согласен, что в итоге получилась ухудшенная версия какой-нить CMS(изначально ориентировался на django с вомзожностью создания своих объектов) и bromzh действительно грамотно расписал технические моменты и посоветовал технологии, которые необходимо использовать.


  1. alarchikov
    28.07.2016 11:55

    Очень многообещающее начало с потрясающей идеей — личная big data. По сути как развитие идеи не просто еще один дневник, но максимально возможно автоматическая система хранящая любую информацию с которой сталкивается и которую генерирует конкретный индивидуум. И в перспективе автоматический анализ данной информации с выдачей рекомендаций в зависимости от поставленных целей. Сфера применения практически безгранична. Дальнейшее масштабирование для многих пользователей и групп с решением чисто технических/архитектурных вопросов и вопросов конфиденциальности хранимых данных видится вполне решаемым. Главное сохранить фокус на ключевой идее.

    Тем больше жаль, что перешло все в практическую реализацию в виде еще_одного_todo_менеджера, коих десятки и сотни. Может быть не тратить время на изучение-разработку того, что уже давно написано, а уделить внимание проработке концепции и основным алгоритмам реализации того, что попало в раздел «мечты»? С удовольствием почитал бы в продолжении о развитии предложенной идеи.


    1. istulenkov
      29.07.2016 07:35

      Я бы все-таки называл личная little data, т.к. применительно к одному человеку не может быть столько big-данных :) (но это сугубо как забавный антипод big data, не настаиваю)

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

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

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


  1. killeralex
    28.07.2016 16:20

    Сам занимаюсь подобной идеей (PBD — Private Big Data). Уклон в сторону личного RUP. Т.е. ставишь себе проекты, измеряешь своё состояние, планируешь сроки и уровень нового состояния. Плюс автору статьи — в постановке вопроса. Два плюса комментатору, расписавшему среды для фронтенда и т.п. А если реализуешь гостовский =водопад=, да еще в ФОИВ, то 1) фронтенды/бекэнды не используют 2) другие RAD и ЯВУ.

    Примеры:
    — по п.1.
    — ГОСТы на АСУ и НИОКР + РВшки;
    — другие категории: СУБД, клиент/сервер, ИО, МО, ПО (ОПО/ОСПО/СПО);
    — под интерфейсами понимают протоколы и менюшки.
    — по п.2
    — Qt старых версий (3, 4).


    1. istulenkov
      29.07.2016 07:24

      Да, в целом это то, что я имел ввиду. А есть программы\статьи по PBD в открытом доступе, которые можно смотреть\потестировать?


      1. killeralex
        29.07.2016 07:50

        На стенах у меня расклеены листочки. Пока только в башке.


  1. beavole
    28.07.2016 16:20

    Я в результате долгих мучений к TODO.txt пришёл, там всё: идеи, задачи, снабжение, долги, контакты, основные расходы/доходы, покупки, рацион, распорядок и т.п. Доступен в любой момент по хоткею (выезжает, загруженный в текстовый редактор, как квейковская консоль, поверх всего). Стараюсь вести его так, чтоб, при необходимости, можно было распарсить на сущности/проанализировать.

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